bash字符串大小比较
我自己写的脚本, 个人保留所有版权,禁止商业用途:
(经测试完全可以正常工作)
#!/bin/sh
#bash_str_compare.sh
#ChenJian
if [ $# -ne 2 ]; then
echo "parameters error"
exit 1
fi
str1=$1
str2=$2
equal_len=0
if [ ${#str1} -gt ${#str2} ]; then
CLen=${#str2}
else
CLen=${#str1}
fi
if [ ${#str1} -eq ${#str2} ]; then
equal_len=1
fi
StrPtr=0
while :
do
str1_char_value=`printf "%d" \'${str1:${StrPtr}:1}`
str2_char_value=`printf "%d" \'${str2:${StrPtr}:1}`
if [ ${str1_char_value} -gt ${str2_char_value} ]; then
echo "${str1} is big than ${str2}"
exit 0
elif [ ${str1_char_value} -lt ${str2_char_value} ]; then
echo "${str1} is small than ${str2}"
exit 0
fi
let StrPtr++
if [ ${StrPtr} -ge ${CLen} ]; then
break
fi
done
if [ ${equal_len} -eq 1 ]; then
echo "${str1} is equal to ${str2}"
elif [ ${#str1} -gt ${CLen} ]; then
echo "${str1} is small than ${str2}"
else
echo "${str1} is big than ${str2}"
fi
================================================================================
from:
incomplete
Stranger, this is a very big topic that needs experience - please extend the descriptions and correct the details if you can!
Attention: This is about the Bash-builtin command printf
- however, the description should be nearly identical for an external command that follows POSIX®.
Unlike other documentations, I don't want to redirect you to the manual page for the printf()
C function family. However, if you're more experienced, that should be
the most detailed description for the format strings and modifiers.
Due to mutual exclusive historical implementations, POSIX® recommends to use printf
rather than echo
.
The printf
command provides a method to print preformatted text similar to the printf()
system interface (C function). It's meant as successor for echo
and has far more features and possibilities.
Beside other reasons, POSIX® has a very good argument to recommend it: Both historical main flavours of the echo
command are mutual exclusive, they collide. A “new” command had to be invented to solve the issue.
printf
The text format is given in
, while all arguments the formatstring may point to are given after that, here, indicated by
.
Thus, a typical printf
-call looks like:
printf "Surname: %s\nName: %s\n" "$SURNAME" "$LASTNAME"
where “Surname: %s\nName: %s\n”
is the format specification, and the two variables are passed as arguments, the %s
in the formatstring points to (for every format specifier you give, printf
awaits one argument!).
-v VAR | If given, the output is assigned to the variable VAR instead of printed to stdout (comparable to sprintf() in some way) |
Of course in shell-meaning the arguments are just strings, however,
the common C-notations for number-constants are recognized to give a
number-argument to printf
:
Number-Format | Description |
N | A normal decimal number |
0N | An octal number |
0xN | A hexadecimal number |
0XN | A hexadecimal number |
“X | (a literal double-quote infront of a character): interpreted as number (underlying codeset) don't forget escaping |
'X | (a literal single-quote infront of a character): interpreted as number (underlying codeset) don't forget escaping |
If more arguments than format specifiers
are present, then the format string is re-used until the last argument
is interpreted. If less format specifiers than arguments are present,
then number-formats are set to zero, while string-formats are set to
null (empty).
Also, to minimize surprises, when printf
expects an argument, give it one, not more. I'm talking about shell word splitting, please read if you don't know what I mean.
incomplete
The format string interpretion is derived from the C printf()
function family. Only format specifiers that end in one of the letters diouxXfeEgGcs
are recognized.
To print a literal %
(percent-sign), use %%
in the format string.
Again: Every format specifier expects an associated argument provided!
Format | Description |
%d | Print the associated argument as signed decimal number |
%i | Same as %d |
%o | Print the associated argument as unsigned octal number |
%u | Print the associated argument as unsigned decimal number |
%x | Print the associated argument as unsigned hexadecimal number with lower-case hex-digits (a-f) |
%X | Same as %x , but with upper-case hex-digits (A-F) |
%f | Interpret and print the associated argument as floating point number |
%e | Interpret the associated argument as double, and print it in ±e format |
%E | Same as %e , but with an upper-case E in the printed format |
%g | Interprets the associated argument as double, but prints it like %f or %e |
%G | Same as %g , but print it like %E |
%c | Interprets the associated argument as character: only the first character of a given argument is printed |
%s | Interprets the associated argument literally as string |
%b | Interprets the associated argument as a string and interpreting escape sequences in it |
%q | Prints the associated argument in a format, that it can be re-used as shell-input (escaped spaces etc..) |
Some of the mentioned format specifiers can modify their behaviour by getting a format modifier:
To be more flexible in the output of numbers and strings, the printf
command allows format modifiers. These are specified between the introducting %
and the character that specifies the format:
printf "%50s\n" "This field is 50 characters wide..."
Field output format |
| Any number: specifies a minimum field width, if the text to print is smaller, it's padded with spaces |
# | “Alternative format” for numbers: see table below |
- | Left-bound text printing inb the field (standard is right-bound) |
0 | Pads numbers with zeros, not spaces |
| Pad a positive number with a space, where a minus (- ) is for negative numbers |
+ | Prints all numbers signed (+ for positive, - for negative) |
The “alternative format” modifier #
:
Alternative Format |
%#o | The octal number is printed with a leading zero, unless it's zero itself |
%#x , %#X | The hex number is printed with a leading ”0x ”/”0X ”, unless it's zero |
%#g , %#G | The float number is printed with trailing zeros until the number of digits for the current precision is reached (usually trailing zeros are not printed) |
all number formats except %d , %o , %x , %X | Always print a decimal point in the output, even if no digits follow it |
The precision for a floating- or double-number can be specified by using .
, where
is the number of digits for precision. If
is an asterisk (*
), the precision is read from the argument that precedes the number to print, like (prints 4,3000000000):
printf "%.*f\n" 10 4,3
The format .*N
to specify the N'th argument for precision does not work in Bash.
For strings, the precision specifies the maximum number of
characters to print (i.e. the maximum field width). For integers, it
specifies the number of digits to print (zero-padding!).
print the decimal representation of a hexadecimal number (preserve the sign)
printf ”%d\n” 0×41
printf ”%d\n” -0×41
printf ”%+d\n” 0×41
print the octal representation of a decimal number
this prints a 0, since no argument is specified
print the code number of the character A
printf ”%d\n” \'A
printf ”%d\n” ”'A”
Generate a greeting banner and assign it to the variable GREETER
This small loop prints all numbers from 0 to 127 in
for ((x=0; x <= 127; x++)); do
printf '%3d | %04o | 0x%02x\n' "$x" "$x" "$x"
done
This code here will take a common MAC address and rewrite it into a
well-known format (regarding leading zeros or upper/lowercase of the
hex digits, …):
the_mac="0:13:ce:7:7a:ad"
# lowercase hex digits
the_mac="$(printf "%02x:%02x:%02x:%02x:%02x:%02x" 0x${the_mac//:/ 0x})"
# or the uppercase-digits variant
the_mac="$(printf "%02X:%02X:%02X:%02X:%02X:%02X" 0x${the_mac//:/ 0x})"
incomplete
This code was found in Solaris manpage for echo(1).
Solaris version of /usr/bin/echo
is equivalent to:
printf "%b\n" "$*"
Solaris /usr/ucb/echo
is equivalent to:
if [ "X$1" = "X-n" ]
then
shift
printf "%s" "$*"
else
printf "%s\n" "$*"
fi
Working off the replacement echo, here is a terse implementation of prargs:
printf '"%b"\n' "$0" "$@" | nl -v0 -s": "
================================================================================
from: http://www.ibm.com/developerworks/cn/linux/l-bash-test.html
级别: 中级
Ian Shields, 高级程序员, IBM
2007 年 3 月 16 日
您是否为 Bash shell 中大量的测试和比较选项而困惑呢?这个技巧可以帮助您解密不同类型的文件、算术和字符串测试,这样您就能够知道什么时候使用 test
、
[ ]
、 [[ ]]
、
(( ))
或 if-then-else
了。
Bash
shell 在当今的许多 Linux® 和 UNIX® 系统上都可使用,是 Linux 上常见的默认 shell。Bash
包含强大的编程功能,其中包括丰富的可测试文件类型和属性的函数,以及在多数编程语言中可以使用的算术和字符串比较函数。理解不同的测试并认识到
shell 还能把一些操作符解释成 shell 元字符,是成为高级 shell 用户的重要一步。这篇文章摘自 developerWorks
教程 LPI 102 考试准备,主题 109: Shell、脚本、编程和编译,介绍了如何理解和使用 Bash shell 的测试和比较操作。
这
个技巧解释了 shell 测试和比较函数,演示了如何向 shell 添加编程功能。您可能已经看到过使用 && 和 ||
操作符的简单 shell
逻辑,它允许您根据前一条命令的退出状态(正确退出或伴随错误退出)而执行后一条命令。在这个技巧中,将看到如何把这些基本的技术扩展成更复杂的
shell 编程。
在任何一种编程语言中,学习了如何给变量分配值和传递参数之后,都需要测试这些值和参数。在 shell 中,测试会设置返回的状态,这与其他命令执行的功能相同。实际上,test
是个内置命令!
内置命令 test
根据表达式expr 求值的结果返回 0(真)或 1(假)。也可以使用方括号:test
expr
和 [
expr ] 是等价的。
可以用 $?
检查返回值;可以使用 && 和 || 操作返回值;也可以用本技巧后面介绍的各种条件结构测试返回值。
[ian@pinguino ~]$ test 3 -gt 4 && echo True || echo false false [ian@pinguino ~]$ [ "abc" != "def" ];echo $? 0 [ian@pinguino ~]$ test -d "$HOME" ;echo $? 0
|
在清单 1 的第一个示例中,-gt
操作符对两个字符值之间执行算术比较。在第二个示例中,用 [ ]
的形式比较两个字符串不相等。在最后一个示例中,测试 HOME 变量的值,用单目操作符
-d
检查它是不是目录。
可以用 -eq
、
-ne
、-lt
、 -le
、
-gt
或 -ge
比较算术值,它们分别表示等于、不等于、小于、小于等于、大于、大于等于。
可以分别用操作符 =
、
!=
、<
和
>
比较字符串是否相等、不相等或者第一个字符串的排序在第二个字符串的前面或后面。单目操作符 -z
测试 null 字符串,如果字符串非空 -n
返回 True(或者根本没有操作符)。
说明:shell 也用 <
和
>
操作符进行重定向,所以必须用 \<
或 \>
加以转义。清单 2 显示了字符串测试的更多示例。检查它们是否如您预期的一样。
[ian@pinguino ~]$ test "abc" = "def" ;echo $? 1 [ian@pinguino ~]$ [ "abc" != "def" ];echo $? 0 [ian@pinguino ~]$ [ "abc" \< "def" ];echo $? 0 [ian@pinguino ~]$ [ "abc" \> "def" ];echo $? 1 [ian@pinguino ~]$ [ "abc" \<"abc" ];echo $? 1 [ian@pinguino ~]$ [ "abc" \> "abc" ];echo $? 1
|
表 1 显示了一些更常见的文件测试。如果被测试的文件存在,而且有指定的特征,则结果为 True。
表 1. 一些常见的文件测试
操作符 | 特征 |
---|
-d | 目录 |
-e | 存在(也可以用 -a) |
-f | 普通文件 |
-h | 符号连接(也可以用 -L) |
-p | 命名管道 |
-r | 可读 |
-s | 非空 |
-S | 套接字 |
-w | 可写 |
-N | 从上次读取之后已经做过修改 |
除了上面的单目测试,还可以使用表 2 所示的双目操作符比较两个文件:
表 2. 测试一对文件
操作符 | 为 True 的情况 |
---|
-nt | 测试 file1 是否比 file2 更新。修改日期将用于这次和下次比较。 |
-ot | 测试 file1 是否比 file2 旧。 |
-ef | 测试 file1 是不是 file2 的硬链接。 |
其他一些测试可以用来测试文件许可之类的内容。请参阅 bash 手册获得更多细节或使用 help test
查看内置测试的简要信息。也可以用 help
命令了解其他内置命令。
-o
操作符允许测试利用
set -o
选项
设置的各种 shell 选项,如果设置了该选项,则返回 True (0),否则返回 False (1),如清单 3 所示。
[ian@pinguino ~]$ set +o nounset [ian@pinguino ~]$ [ -o nounset ];echo $? 1 [ian@pinguino ~]$ set -u [ian@pinguino ~]$ test -o nounset; echo $? 0
|
最后,-a
和 -o
选项允许使用逻辑运算符 AND 和 OR 将表达式组合在一起。单目操作符 !
可以使测试的意义相反。可以用括号把表达式分组,覆盖默认的优先级。请记住 shell 通常要在子 shell 中运行括号中的表达式,所以需要用 \( 和
\) 转义括号,或者把这些操作符括在单引号或双引号内。清单 4 演示了摩根法则在表达式上的应用。
[ian@pinguino ~]$ test "a" != "$HOME" -a 3 -ge 4 ; echo $? 1 [ian@pinguino ~]$ [ ! \( "a" = "$HOME" -o 3 -lt 4 \) ]; echo $? 1 [ian@pinguino ~]$ [ ! \( "a" = "$HOME" -o '(' 3 -lt 4 ')' ")" ]; echo $? 1
|
test
命令非常强大,但是很难满足其转义需求以及字符串和算术比较之间的区别。幸运的是,bash 提供了其他两种测试方式,这两种方式对熟悉 C、C++ 或 Java® 语法的人来说会更自然些。
(( ))
复合命令 计算算术表达式,如果表达式求值为 0,则设置退出状态为 1;如果求值为非 0 值,则设置为 0。不需要对
((
和 ))
之间的操作符转义。算术只对整数进行。除 0 会产生错误,但不会产生溢出。可以执行 C 语言中常见的算术、逻辑和位操作。
let
命令也能执行一个或多个算术表达式。它通常用来为算术变量分配值。
[ian@pinguino ~]$ let x=2 y=2**3 z=y*3;echo $? $x $y $z 0 2 8 24 [ian@pinguino ~]$ (( w=(y/x) + ( (~ ++x) & 0x0f ) )); echo $? $x $y $w 0 3 8 16 [ian@pinguino ~]$ (( w=(y/x) + ( (~ ++x) & 0x0f ) )); echo $? $x $y $w 0 4 8 13
|
同使用 (( ))
一样,利用复合命令 [[ ]]
可以对文件名和字符串使用更自然的语法。可以用括号和逻辑操作符把 test
命令支持的测试组合起来。
[ian@pinguino ~]$ [[ ( -d "$HOME" ) && ( -w "$HOME" ) ]] && > echo "home is a writable directory" home is a writable directory
|
在使用 =
或 !=
操作符时,复合命令 [[
还能在字符串上进行模式匹配。匹配的方式就像清单 7 所示的通配符匹配。
[ian@pinguino ~]$ [[ "abc def .d,x--" == a[abc]*\ ?d* ]]; echo $? 0 [ian@pinguino ~]$ [[ "abc def c" == a[abc]*\ ?d* ]]; echo $? 1 [ian@pinguino ~]$ [[ "abc def d,x" == a[abc]*\ ?d* ]]; echo $? 1
|
甚至还可以在 [[
复合命令内执行算术测试,但是千万要小心。除非在 ((
复合命令内,否则
<
和 >
操作符会把操作数当成字符串比较并在当前排序序列中测试它们的顺序。清单 8 用一些示例演示了这一点。
[ian@pinguino ~]$ [[ "abc def d,x" == a[abc]*\ ?d* || (( 3 > 2 )) ]]; echo $? 0 [ian@pinguino ~]$ [[ "abc def d,x" == a[abc]*\ ?d* || 3 -gt 2 ]]; echo $? 0 [ian@pinguino ~]$ [[ "abc def d,x" == a[abc]*\ ?d* || 3 > 2 ]]; echo $? 0 [ian@pinguino ~]$ [[ "abc def d,x" == a[abc]*\ ?d* || a > 2 ]]; echo $? 0 [ian@pinguino ~]$ [[ "abc def d,x" == a[abc]*\ ?d* || a -gt 2 ]]; echo $? -bash: a: unbound variable
|
虽然使用以上的测试和 &&
、
||
控制操作符能实现许多编程,但 bash 还包含了更熟悉的 “if, then, else” 和 case 结构。学习完这些之后,将学习循环结构,这样您的工具箱将真正得到扩展。
bash 的 if
命令是个复合命令,它测试一个测试或命令($?
)的返回值,并根据返回值为 True(0)或 False(不为 0)进行分支。虽然上面的测试只返回 0 或 1 值,但命令可能返回其他值。请参阅
LPI 102 考试准备,主题 109: Shell、脚本、编程和编译 教程学习这方面的更多内容。
Bash 中的 if
命令有一个
then
子句,子句中包含测试或命令返回 0 时要执行的命令列表,可以有一个或多个可选的
elif
子句,每个子句可执行附加的测试和一个
then
子句,子句中又带有相关的命令列表,最后是可选的 else
子句及命令列表,在前面的测试或
elif
子句中的所有测试都不为真的时候执行,最后使用 fi
标记表示该结构结束。
使用迄今为止学到的东西,现在能够构建简单的计算器来计算算术表达式,如清单 9 所示:
[ian@pinguino ~]$ function mycalc () > { > local x > if [ $# -lt 1 ]; then > echo "This function evaluates arithmetic for you if you give it some" > elif (( $* )); then > let x="$*" > echo "$* = $x" > else > echo "$* = 0 or is not an arithmetic expression" > fi > } [ian@pinguino ~]$ mycalc 3 + 4 3 + 4 = 7 [ian@pinguino ~]$ mycalc 3 + 4**3 3 + 4**3 = 67 [ian@pinguino ~]$ mycalc 3 + (4**3 /2) -bash: syntax error near unexpected token `(' [ian@pinguino ~]$ mycalc 3 + "(4**3 /2)" 3 + (4**3 /2) = 35 [ian@pinguino ~]$ mycalc xyz xyz = 0 or is not an arithmetic expression [ian@pinguino ~]$ mycalc xyz + 3 + "(4**3 /2)" + abc xyz + 3 + (4**3 /2) + abc = 35 |
这个计算器利用 local
语句将 x 声明为局部变量,只能在
mycalc
函数的范围内使用。let
函数具有几个可用的选项,可以执行与它密切关联的
declare
函数。请参考 bash 手册或使用 help let
获得更多信息。
如清单 9 所示,需要确保在表达式使用 shell 元字符 —— 例如(、)、*、> 和 < 时 —— 正确地对表达式转义。无论如何,现在有了一个非常方便的小计算器,可以像 shell 那样进行算术计算。
在清单 9 中可能注意到 else
子句和最后的两个示例。可以看到,把 xyz
传递给 mycalc 并没有错误,但计算结果为 0。这个函数还不够灵巧,不能区分最后使用的示例中的字符值,所以不能警告用户。可以使用字符串模式匹配测试(例如
[[ ! ("$*" == *[a-zA-Z]* ]]
,或使用适合自己范围的形式)消除包含字母表字符的表达式,但是这会妨碍在输入中使用 16 进制标记,因为使用 16 进制标记时可能要用 0x0f 表示 15。实际上,shell 允许的基数最高为 64(使用
base#value
标记),所以可以在输入中加入 _ 和 @ 合法地使用任何字母表字符。8 进制和 16 进制使用常用的标记方式,开头为 0 表示八进制,开头为 0x 或 0X 表示 16 进制。清单 10 显示了一些示例。
[ian@pinguino ~]$ mycalc 015 015 = 13 [ian@pinguino ~]$ mycalc 0xff 0xff = 255 [ian@pinguino ~]$ mycalc 29#37 29#37 = 94 [ian@pinguino ~]$ mycalc 64#1az 64#1az = 4771 [ian@pinguino ~]$ mycalc 64#1azA 64#1azA = 305380 [ian@pinguino ~]$ mycalc 64#1azA_@ 64#1azA_@ = 1250840574 [ian@pinguino ~]$ mycalc 64#1az*64**3 + 64#A_@ 64#1az*64**3 + 64#A_@ = 1250840574
|
对输入进行的额外处理超出了本技巧的范围,所以请小心使用这个计算器。
elif
语句非常方便。它允许简化缩进,从而有助于脚本编写。在清单 11 中可能会对 type
命令在
mycalc
函数中的输出感到惊讶。
[ian@pinguino ~]$ type mycalc mycalc is a function mycalc () { local x; if [ $# -lt 1 ]; then echo "This function evaluates arithmetic for you if you give it some"; else if (( $* )); then let x="$*"; echo "$* = $x"; else echo "$* = 0 or is not an arithmetic expression"; fi; fi } |
当然,也可以只用
$((
表达式
))
和
echo
命令进行 shell 算术运算,如清单 12 所示。这样就不必学习关于函数或测试的任何内容,但是请注意 shell 不会解释元字符,例如 *,因此元字符不能在
((
表达式
))
或
[[
表达式
]]
中那样正常发挥作用。
[ian@pinguino ~]$ echo $((3 + (4**3 /2))) 35 |
如果想了解在 Linux 中进行 Bash 脚本编程的更多内容,请阅读本文所属的教程 “LPI 102 考试准备,主题 109: Shell、脚本、编程和编译”,或查看下面的其他 参考资料。请不要忘记
给本页打分。
学习获得产品和技术-
请订购 SEK for Linux,共有两张 DVD,包含最新的用于 Linux 的 IBM 试用软件,包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。
- 可以直接从 developerWorks 下载
IBM 试用软件。
讨论 |
| | Ian
Shields 为 developerWorks Linux 专区的许多 Linux 项目工作。他是 IBM 北卡罗莱那州 Research
Triangle Park 的一名高级程序员。他于 1973 年作为一名系统工程师加入 IBM
位于澳大利亚堪培拉的子公司。之后,在加拿大蒙特利尔和北卡罗莱那州 RTP 从事通信系统和普及运算。他拥有多项专利。他毕业于
Australian National University,本科学位是纯数学和哲学。他拥有北卡罗来纳州立大学的计算机学士和博士学位。 |
================================================================================
from:
bash中字符串的处理
2007年02月28日 社区交流
关键字: 文本模式 Puppy Linux Linux服务器 XFS devfs VM
本文详细介绍bash中字符串的处理
1.得到字符串长度
方法一:
$echo ${#variable}
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ echo ${#x}
14方法二:
$expr length "$variable"
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ expr length "$x"
14方法三:
$expr "$variable" : ".*"
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ expr "$x" : ".*"
142.查找字符串子串位置
方法:
$expr index "$variable" "substring"
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ expr index "$x" "is"
3
zhyfly: ~$ expr index "$x" "t"
1(ps:如果出现重复,好象只能查到第一个,第二个,第三个,...,怎么查到呢???)
3.得到字符串子字符串
方法一:
$echo ${variable:position:length}
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ echo ${x:1:5}
his i方法二:
$expr substr "$variable" startposition length
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ expr substr "$x" 1 5
this(ps:注意方法一和方法二中位置的区别!)
4.匹配正则表达式之匹配长度
方法:
$expr match "$x" "string"
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ expr match "$x" "his"
0
zhyfly: ~$ expr match "$x" "this"
4
zhyfly: ~$ expr match "$x" "."
15.字符串的掐头去尾
方法:
$echo ${variable#startletter*endletter} # #表示掐头,因为键盘上#在$前面,一个表示最小匹配
$echo ${variable##tartletter*endletter} 两个表示最大匹配
$echo ${variable%startletter*endletter} # %表示去尾,因为键盘上%在$后面,一个表示最小匹配
$echo ${variable%%startletter*endletter} 两个表示最大匹配
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ echo ${x#t}
his is a test
zhyfly: ~$ echo ${x#t*h}
is is a test
zhyfly: ~$ echo ${x#t*s}
is a test
zhyfly: ~$ echo ${x##t*s}
t
zhyfly: ~$ echo ${x%t}
this is a tes
zhyfly: ~$ echo ${x%s*t}
this is a te
zhyfly: ~$ echo ${x%e*t}
this is a t
zhyfly: ~$ echo ${x%%i*t}
th
6.字符(串)的替换
方法:
$echo ${variable/oldletter/newletter} #替换一个
$echo ${variable//oldletter/newletter} #替换所有
code:
PHP 代码:zhyfly: ~$ x="this is a test"
zhyfly: ~$ echo ${x/i/m}
thms is a test
zhyfly: ~$ echo ${x//i/m}
thms ms a tes
================================================================================
from:
[精华] bash 编程
作者:jiupima 发表于:2005-07-22 16:29:17
【发表评论】【查看原文】【SCO UNIX讨论区】【关闭】
Bash 编程
一. Bash特殊字符
1. 通配符:
*:匹配任何字符串
?:匹配任何单个字符
集合运算符:用一些单个字、一个连续范围或断续的字符集合作为通配符
[set]:用字符集合作通配符匹配单个字符,如:[aeiou],[a-o],[a-h, w-z]
[!set]:除了集合外的所有字符组成的集合作通配符
2. 花括号展开式(可以嵌套):
格式:[前导字符串]{字符串1[{嵌套字符串1…}] [, 字符传2…]}[后继字符串]
如:c{a{r, t, n}, b{r, t, n}}s 就等于 cars cats cans cbrs cbts cbns
3. 其它特殊字符:
< :输入重定向
>; :输出重定向(没有文件则创建,有则覆盖)
>;>; :输出重定向(没有则创建,有则追加到文件尾部)
( :子shell开始,子shell继承父shell部分环境变量
) :子shell结束
{ :命令块开始,由当前shell执行,保留所有环境变量
} :命令块结束
| :管道
\ :引用后面的单个字符
‘ :强引用字符串,不解释特殊字符
“ :弱引用字符串,解释所有特殊字符
~ :根目录
` :命令替换
; :命令分隔符(命令终止符),运行在一行里执行多条命令
# :行注释
$ :变量表达式
& :在后台执行命令
* :字符串通配符
? :单个字符通配符
二. Bash变量
1. 自定义变量
用户自定义的变量由字母、数字和下划线组成,并且变量名的第一个字符不能为数字,且变量名大小写敏感。
varname=value 注意bash不能在等号两侧留空格
shell语言是非类型的解释型语言,给一个变量赋值实际上就是定义了变量,而且可以赋不同类型的值。引用变量有两种方式,$varname和${varname},为防止变量在字符串中产生歧义建议使用第二种方式,引用未定义的变量其值为空。
为一个变量赋值一个串,需要用到引号,注意`、’、”的不同,``相当于$()
为了使变量可以在其它进程中使用,需要将变量导出:export varname
2. 环境变量
可以用set命令给变量赋值或查看环境变量值,使用unset命令清除变量值,使用export导出变量将可以使其它进程访问到该环境变量。
3. 位置变量
位置变量对应于命令行参数,其中$0为脚本名称,$1为第一个参数,依次类推,参数超过9个必须使用${}引用变量。shell保留这些变量,不允许用户以另外的方式定义它们,传给脚本或函数的位置变量是局部和只读的,而其余变量为全局的(可以用local关键字声明为局部)。
4. 其它变量
$? :保存前一个命令的返回码
$- :在Shell启动或使用set命令时提供选项
$$ :当前shell的进程号
$! :上一个子进程的进程号
$# :传给脚本或函数的参数个数,即位置变量数减1,不含脚本名称。
$* :传给脚本或函数的参数组成的单个字符串,即除脚本名称后从第一个参数开始的字符串,每个参数以$IFS分隔(一般内部域分隔符$IFS为1空格)。形同”…”
$@ :传给脚本或函数的参数列表,这些参数被表示为多个字符串。形同”” “” “”…。$*和$@之间的不同方便使用两种方法处理命令行参数,但是在打印时参数外观没有区别。
如: #vi posparm.sh
function cutparm
{echo –e “inside cntparm: $# parms: $*\n”}
cntparm “$*”
cntparm “$@”
#./posparm.sh abc bca cab
inside cntparm: 1 parms: abc bca cab
inside cntparm: 3 parms: abc bca cab
三. Bash操作符
1. 字符串操作符(替换操作符)
${var:-word} 如果var存在且不为空,返回它的值,否则返回word
${var:=word} 如果var存在且不为空,返回它的值,否则将word赋给var, 返回它的值
${var:+word} 如果var存在且不为空,返回word,否则返回空
${var:?message} 如果var存在且不为空,返回它的值,
否则显示“bash2:$var:$message”,然后退出当前命令或脚本
${var:offset[]} 从offset位置开始返回var的一个长为length的子串,
若没有length,则默认到var串末尾
2. 模式匹配操作符
${var#pattern} 从var头部开始,删除和pattern匹配的最短模式串,然后返回 剩余串
${var##pattern} 从var头部开始,删除和pattern匹配的最长模式串,然后返回 剩余串,basename path=${path##*/}
${var%pattern} 从var尾部开始,删除和pattern匹配的最短模式串,然后返回 剩余串,dirname path=${path%/*}
${var%%pattern} 从var尾部开始,删除和pattern匹配的最长模式串,然后返回 剩余串
${var/pattern/string} 用string替换var中和pattern匹配的最长模式串
四. Shell中条件和test命令
Bash可以使用[ … ]结构或test命令测试复杂条件
格式:[ expression ] 或 test expression
返回一个代码,表明条件为真还是为假,返回0为真,否则为假。
注:左括号后和右括号前空格是必须的语法要求
1. 文件测试操作符
-d file file存在并且是一个目录
-e file file存在
-f file file存在并且是一个普通文件
-g file file存在并且是SGID(设置组ID)文件
-r file 对file有读权限
-s file file存在并且不为空
-u file file存在并且是SUID(设置用户ID)文件
-w file 对file有写权限
-x file 对file有执行权限,如果是目录则有查找权限
-O file 拥有file
-G file 测试是否是file所属组的一个成员
-L file file为符号链接
file1 –nt file2 file1比file2新
file1 –ot file2 file1比file2旧
2. 字符串操作符
str1=str2 str1和str2匹配
str1!=str2 str1和str2不匹配
str1
str1>;str2 str1大于str2
-n str str的长度大于0(不为空)
-z str str的长度为0(空串)
3. 整数操作符
var1 –eq var2 var1等于var2
var1 –ne var2 var1不等于var2
var1 –ge var2 var1大于等于var2
var1 –gt var2 var1大于var2
var1 –le var2 var1小于等于var2
var1 –lt var2 var1小于var2
4. 逻辑操作符
!expr 对expr求反
expr1 && expr2 对expr1与expr2求逻辑与,当expr1为假时不再执行expr2
expr1 || expr2 对expr1与expr2求逻辑或,当expr1为真时不再执行expr2
注:另一种逻辑操作符 逻辑与expr1 –a expr2 逻辑或expr1 –o expr2
五. Shell流控制
1. 条件语句:if
if 条件 IFS=:
then for dir in $PATH
语句 do
[elif 条件 if [ -O dir ]; then
语句] echo –e “\tYou own $dir”
[else else
语句] echo –e “\tYou don’t own $dir”
fi fi
2. 确定性循环:for done
for value in list for docfile in /etc/* /usr/etc/*
do do
statements using $value cp $docfile ${docfile%.doc}.txt
done done
注:for var;… 相当于for var in “$@”;…
3. 不确定性循环:while和until
while 条件 until 条件
do do
语句 语句
done done
count=1 count=1
while [ -n “$*” ] until [ -z “$*” ]
do do
echo "parameter $count" echo "parameter $count"
shift shift
count='expr $count + 1' count='expr $count + 1'
done done
条件为真执行循环体 条件为假执行循环体
注:整数变量的定义与算法
declare –i idx 定义整数变量 使用$(())无需定义
idx=1
while [ $idx!=150 ]
do
cp somefile somefile.$idx
idx=$idx+1 整数算法 idx=$(( $idx+1 ))
done
另一种算法 echo $(( 100/3 )) 将加减乘除表达式放入$(())中
4. 选择结构:case和select
case 表达式 in 表达式和模式依次比较,执行第一个匹配的模式
模式1) ;;使程序控制流跳到esac后执行,相当于break
语句;; 允许表达式和含有通配符的模式进行匹配
模式2)
语句;;
……
[*)
语句]
esac
select value [ in list ] 按list列表自动生成菜单
do 若没有list则默认为位置变量
statements using $value
done
如:IFS=: 设置域分隔符为:号
PS3=”choice>;” 改变select默认提示符
clear
select dir in $PATH
do
if [ $dir ]; then
cnt=$(ls –Al $dir | wc -l)
echo “$cnt files in $dir”
else
echo “No such choice !”
fi
echo –e “\npress ENTER to continue, CTRL-C to quit”
read 使程序按回车继续,ctrl+c退出
clear
done
5. 命令shift
将存放在位置变量中的命令行参数依次向左传递
shift n 命令行参数向左传递n个串
六. Shell函数
定义: function fname fname ()
{ {
commands commands
} }
调用:fname [ parm1 parm2 parm3 ... ]
说明: 函数在使用前定义,两种定义功能相同
函数名和调用函数参数成为函数的位置变量
函数中的变量应该使用local声明为局部变量
七. 输入输出
限于篇幅,这里不讨论所有输入输出操作符和功能
1.I/O重定向
< :输入重定向
>; :输出重定向(没有文件则创建,有则覆盖)
>;>; :输出重定向(没有则创建,有则追加到文件尾部)
<< :输入重定向(here文档)
格式: command << label
input…
label
说明: 使一个命令的输入为一段shell脚本(input…),直到标号(label)结束
如: cat < $HOME/.profile >; out
echo “add to file end !” >;>; $HOME/.profile
ftp:USER=anonymous
PASS=YC@163.com
ftp –i –n << END -i:非交互模式 -n:关闭自动登录
open ftp.163.com
user $USER $PASS
cd /pub
close
END END标记输入结束
2.字符串I/O操作
字符串输出:echo
命令选项: -e:启动转义序列 -n:取消输出后换行
转义序列: \a:Alt/Ctrl+G(bell) \b:退格Backspace/Ctrl+H
\c:取消输出后换行 \f:Formfeed/Ctrl+J
\r:Return/Ctrl+M \v:Vertical tab
\n:八进制ASCII字符 \\:单个\字符 \t:Tab制表符
字符串输入:read
可以用于用户交互输入,也可以用来一次处理文本文件中的一行
命令选项: -a:将值读入数组,数组下标从0开始
-e:使用GNU的readline库进行读入,允许bash的编辑功能
-p:在执行读入前打印提示
如: IFS=:
read –p “start read from file . filename is : \c” filename
while read name pass uid gid gecos home shell < filename
do
echo –e “name : $name\npass : $pass\n”
done
说明:如果行的域数大于变量表的变量数,则后面的域全部追加给最后的变量
八. 命令行处理
命令行处理命令:getopts
有两个参数,第一个为字母和冒号组成的选项列表字符串,第二个为一个变量名
选项列表字符串以冒号开头的选项字母排列组成,如果一选项需要一个参数则该选项字母后跟一个冒号
getopts分解第一参数,依次将选项摘取出来赋给第二个参数变量
如果某选项有参数,则读取参数到内置变量OPTARG中
内置变量OPTIND保存着将被处理的命令行参数(位置参数)的数值
选项列表处理完毕getopts返回1,否则返回0
如: while getopts “:xy:z:” opt
do
case $opt in
x) xopt=’-x set’ ;;
y) yopt=”-y set and called with $OPTARG” ;;
z) zopt=”-z set and called with $OPTARG” ;;
\?) echo ‘USAGE: getopts.sh [-x] [-y arg] [-z arg] file…’
exit 1
esac
done
shift ($OPTING-1) 将处理过的命令行参数移去
echo ${xopt: -‘did not use –x‘}
echo ${yopt: -‘did not use –y‘}
echo ${zopt: -‘did not use –z‘}
echo “Remaining command-line arguments are :”
for f in “$@”
do
echo –e “\t$f\n”
done
九. 进程和作业控制
信号处理命令:trap
格式:trap command sig1 sig2 …
trap可以识别30多种信号,如中断(Ctrl+c)、挂起(Ctrl+z)等,可以使用kill -l查看信号清单
当脚本接受到信号sig1、sig2等,trap就执行命令command,command完成后脚本重新执行
信号可以通过名称或数字来标识
作业控制命令:bg、fg
bg:显示后台进程,即用Ctrl+z挂起或‘命令 &’执行的进程
fg:将后台进程转到前台执行
kill –9 %n:杀掉第n个后台进程
附录:
一. Bash支持的命令行参数
-a 将所有变量输出
-c "string"从string中读取命令
-e 使用非交互式模式
-f 禁止shell文件名产生
-h 定义
-i 交互式模式
-k 为命令的执行设置选项
-n 读取命令但不执行
-r 受限模式
-s 命令从标准输入读取
-t 执行一命令,然后退出shell
-u 在替换时,使用未设置的变量将会出错
-v 显示shell的输入行
-x 跟踪模式,显示执行的命令
许多模式可以组合起来用,使用set可以设置或取消shell的选项来改变shell环境。打开选项用"-",关闭选项用"+",若显示Shell中已经设置的选项,执行: $echo $-
二. .profile中shell的环境变量意思如下:
CDPATH 执行cd命令时使用的搜索路径
HOME 用户的home目录
IFS 内部的域分割符,一般为空格符、制表符、或换行符
MAIL 指定特定文件(信箱)的路径,有UNIX邮件系统使用
PATH 寻找命令的搜索路径(同dos的config.sys的 path)
PS1 主命令提示符,默认是"$"
PS2 从命令提示符,默认是">;"
TERM 使用终端类型
================================================================================
from:
到长度
%x="abcd"
#方法一
%expr length $x
4
# 方法二
%echo ${#x}
4
# 方法三
%expr "$x" : ".*"
4
# expr 的帮助
# STRING : REGEXP anchored pattern match of REGEXP in STRING
查找子串
%expr index $x "b"
2
%expr index $x "a"
1
%expr index $x "b"
2
%expr index $x "c"
3
%expr index $x "d"
4
得到子字符串
# 方法一
# expr startpos length
%expr substr "$x" 1 3
abc
%expr substr "$x" 1 5
abcd
%expr substr "$x" 2 5
bcd
# 方法二
# ${x:pos:lenght}
%echo ${x:1}
bcd
%echo ${x:2}
cd
%echo ${x:0}
abcd
%echo ${x:0:2}
ab
%pos=1
%len=2
%echo ${x:$pos:$len}
bc
匹配正则表达式
# 打印匹配长度
%expr match $x "."
1
%expr match $x "abc"
3
%expr match $x "bc"
0
字符串的掐头去尾
%x=aabbaarealwwvvww
%echo "${x%w*w}"
aabbaarealwwvv
%echo "${x%%w*w}"
aabbaareal
%echo "${x##a*a}"
lwwvvww
%echo "${x#a*a}"
bbaarealwwvvww
其中 , # 表示掐头, 因为键盘上 # 在 $ 的左面。
其中 , % 表示%, 因为键盘上 % 在 $ 的右面。
单个的表示最小匹配,双个表示最大匹配。
也就是说,当匹配的有多种方案的时候,选择匹配的最大长度还是最小长度。
字符串的替换
%x=abcdabcd
%echo ${x/a/b} # 只替换一个
bbcdabcd
%echo ${x//a/b} # 替换所有
bbcdbbcd
不可以使用 regexp , 只能用 * ? 的文件扩展方式。
================================================================================
================================================================================
================================================================================
================================================================================
================================================================================
================================================================================
================================================================================
================================================================================