上回梳理 了Linux Shell编程中 () 、$()和 (())的用法,现在接着梳理 [] 和[[]]的用法。
1 单中括号(方括号)[]
1.1 检测某个条件是否成立
[和test等同,是 Shell 内置命令,用来检测某个条件是否成立。条件成立时退出状态为 0,否则为非 0 值。
1.1.1 字符串比较运算
1.1.1.1 ==(或=) 和 !=
Test和[]中,可用的比较运算符只有 ==(或=) 和 !=,两者都是用于字符串比较的,不可用于整数比较。
- 在不引起歧义的情况下,[]中的变量名可以不加$前缀。
实例:
我们先定义字符串s1="abc"和s2="def"
然后在[]中分别使用==和!=来在bash和zsh进行测试。
1.在bash中
[cs ~]$ s1="abc"; s2="def"
[cs ~]$ echo $[ $s1 != $s2 ]
0
[cs ~]$ if [ $s1 != $s2 ] ; then echo s1=$s1; else echo s2=$s2; fi
s1=abc
[cs ~]$ echo $[ $s1 == $s2 ]
1
[cs ~]$ if [ $s1 == $s2 ] ; then echo s1=$s1; else echo s2=$s2; fi
s2=def
[cs ~]$ echo $[ s1 == s2 ]
1
[cs ~]$
2.在zsh中
cs @ edu $ s1="abc"
cs @ edu $ s1="abc";s2="def"
cs @ edu $ echo $[ $s1 != $s2 ]
0
cs @ edu $ if [ $s1 != $s2 ] ; then echo s1=$s1; else echo s2=$s2; fi
else>
cs @ edu $ echo $[ $s1 == $s2 ]
1
cs @ edu $ if [ $s1 == $s2 ] ; then echo s1=$s1; else echo s2=$s2; fi
else>
cs @ edu $ echo $[ s1 == s2 ]
1
cs @ edu $
1.1.1.2 < 和 >
对字符串比较,是否直接可用使用大于号(>)和小于号(<)呢?
1.在bash中
[cs ~]$ s1="abc"
[cs ~]$ s2="def"
[cs ~]$ echo $[ $s1 > $s2 ]
0
[cs ~]$ [ $s1 \> $s2 ]
[cs ~]$ echo $?
1
[cs ~]$ echo $[ $s1 < $s2 ]
0
[cs ~]$ [ $s1 \< $s2 ]
[cs ~]$ echo $?
0
[cs ~]$
在上面的例子中,我们先定义了字符串变量s1="abc"和 s2="def",然后在[]中直接使用 > 和 < 对s1和s2进行比较,显示结果都是1,明显有问题。
当我们在[]中使用 \> 和 \< 来对s1和s2进行比较,结果分别是1和0,这才是正确的结果。
可见,在bash中,对于字符串比较,可以使用转义形式用大于号(>)和小于号(<)。
2.在zsh中
user # cs zsh $ s1="abc"
user # cs zsh $ s2="def"
user # cs zsh $ echo $[ $s1 > $s2 ]
0
user # cs zsh $ [ $s1 \> $s2 ]
zsh: condition expected: >
user # cs zsh $ echo $?
1
user # cs zsh $ echo $[ $s1 < $s2 ]
0
user # cs zsh $ [ $s1 \< $s2 ]
zsh: condition expected: <
user # cs zsh $ echo $?
1
在上面的例子中,我们同样先定义了字符串变量s1="abc"和 s2="def",然后在[]中直接使用 > 和 < 对s1和s2进行比较,显示结果都是0,与bash中不同,但同样明显有问题。
当我们在[]中使用 \> 和 \< 来对s1和s2进行比较,zsh不支持。
字符范围。用作正则表达式的一部分,描述一个匹配的字符范围。作为test用途的中括号内不能使用正则。
1.1.2 整数比较运算
1.1.2.1 -eq,-gt等
Test和[]中, 整数比较可以使用-eq,-gt这类形式。
1.1.2.1.1 在bash中
[cs ~]$ i=1; let i++; echo i=$i; j=12;let j--;echo j=$j
i=2
j=11
[cs~]$ [ $i -lt $j ]
[cs ~]$ echo $?
0
[cs ~]$ [ $i -gt $j ]
[cs ~]$ echo $?
1
1.1.2.1.2 在zsh中
cs @ edu $ i=1; let i++; echo i=$i; j=12;let j--;echo j=$j
i=2
j=11
cs @ edu $ [ $i -lt $j ]
cs @ edu $ echo $?
0
cs @ edu $ [ $i -gt $j ]
cs @ edu $ echo $?
1
1.1.2.2 < 和 >
在大多编程变语言中,对Linux shell中的整数比较,是否直接可用使用大于号(>)和小于号(<)呢?
1.1.2.1.1在bash中
[cs ~]$ i=1; let i++; echo i=$i; j=12;let j--;echo j=$j
i=2
j=11
[cs ~]$ echo $[ i > j ]
0
[cs ~]$ echo $[ i < j ]
1
[cs ~]$ echo $[ i \< j ]
bash: i \< j : syntax error: invalid arithmetic operator (error token is "\< j ")
[cs ~]$ [ i \< j ]
[cs ~]$ echo $?
0
[cs ~]$ [ i \> j ]
[cs ~]$ echo $?
1
在上面的实例中,我们定义了整数变量i和j,
先直接使用 > 和 < 来比较i和j,结果分别是0和1,这个结果按字符串来比较是对的,但按整数来比较是错误的。
接着我们使用 \< 和 \> 来对i和j进行比较,结果分别是0和1,正确。
以下是按字符串来比较的结果。
[cs ~]$ i='2'; j="11"
[cs ~]$ echo $[ i > j ]
0
[cs ~]$ echo $[ i < j ]
1
1.1.2.1.2 在zsh中
cs @ edu $ i=1; let i++; echo i=$i; j=12;let j--;echo j=$j
i=2
j=11
cs @ edu $ echo $[ j > j ]
0
cs @ edu $ echo $[ j < j ]
0
cs @ edu $ echo $[ j \< j ]
zsh: bad math expression: illegal character: \
cs @ edu $ echo $[ j \> j ]
zsh: bad math expression: illegal character: \
在上面的实例中,我们同样是定义了整数变量i和j,
先直接使用 > 和 < 来比较i和j,结果都是0,显示有问题。
接着我们使用 \< 和 \> 来对i和j进行比较,结果zsh不支持。
1.1.3 逻辑运算
- [ ]中的逻辑与 使用 -a 表示(and),和逻辑或使用 -o 表示(or)。
- [ ]之间的逻辑与 使用 && 表示(and),和逻辑或使用 || 表示(or)。
1.1.3.1 在bash中
[cs ~]$ s1='a';s2='b';s3='a'
[cs ~]$ [ $s1 == $s2 -o $s1 == $s3 ]
[cs ~]$ echo $?
0
[cs ~]$ [ $s1 == $s2 ] || [ $s1 == $s3 ]
[cs ~]$ echo $?
0
[cs ~]$ [ $s1 == $s2 -a $s1 == $s3 ]
[cs ~]$ echo $?
1
[cs ~]$ [ $s1 == $s2 ] && [ $s1 == $s3 ]
[cs ~]$ echo $?
1
在上面的实例中,我们先定义了三个字符串变量: s1='a';s2='b';s3='a'
然后执行 [ $s1 == $s2 -o $s1 == $s3 ] , s1 == $s2 结果为1,$s1 == $s3结果为0,由于我们使用的是 -o (or ),所以结果为0
接着用命令 echo $? 来显示结果:0
然后的 [ $s1 == $s2 ] || [ $s1 == $s3 ] 和 [ $s1 == $s2 -o $s1 == $s3 ]是一样的。
接着执行 [ $s1 == $s2 -a $s1 == $s3 ] ,s1 == $s2 结果为1,$s1 == $s3结果为0,由于我们使用的是 -a (and ),所以结果为1
最后用命令 echo $? 来显示结果:0
1.1.3.2 在zsh中
cs @ edu zsh $ s1='a';s2='b';s3='a'
cs @ edu zsh $ [ $s1 == $s2 -o $s1 == $s3 ]
zsh: = not found
cs @ edu zsh $ [ $s1 = $s2 -o $s1 = $s3 ]
cs @ edu zsh $ echo $?
0
cs @ edu zsh $ [ $s1 == $s2 ] || [ $s1 == $s3 ]
zsh: = not found
cs @ edu zsh $ [ $s1 = $s2 ] || [ $s1 = $s3 ]
cs @ edu zsh $ echo $?
0
cs @ edu zsh $ [ $s1 = $s2 -o $s1 = $s3 ]
cs @ edu zsh $ echo $?
0
cs @ edu zsh $ [ $s1 = $s2 ] && [ $s1 = $s3 ]
cs @ edu zsh $ echo $?
1
上面的实例与bash中是一样的,不过zsh不支持 == ,我们改为 = 。
1.2 引用数组中每个元素
对数组来说,中括号可以用来按下标索引访问数组元素。
1.2.1 在bash中
[cs ~]$ a=(1 2 3)
[cs ~]$ echo ${a[1]}
2
[cs ~]$ echo ${a[*]}
1 2 3
在上面实例中,我们先定义数组 a=(1 2 3)
然后用命令 echo ${a[1]} 显示数组中的第2个元素,bash中数组下标从0开始。
接着用命令 echo ${a[*]} 显示数组中的所有元素。
1.2.2 在zsh中
cs @edu zsh $ a=(1 2 3)
cs@edu zsh $ echo $a[1]
1
cs @edu zsh $ echo $a[*]
1 2 3
cs @edu zsh $ echo ${a[1]}
1
cs @edu zsh $ echo ${a[*]}
1 2 3
在上面实例中,我们先定义数组 a=(1 2 3)
然后用命令 echo ${a[1]} 显示数组中的第1个元素,bash中数组下标从1开始。
接着用命令 echo ${a[*]} 显示数组中的所有元素。
2 双中括号(方括号)[[]]
[[ ]]是 Shell 内置关键字,它的功能和 [] 或 test 命令类似,也用来检测某个条件是否成立。
[[ ]] 是 [] 或 test 的升级版,对细节进行了优化,并且扩展了一些功能。
- [] 或 test 能做到的,[[ ]] 也能做到,而且 [[ ]] 做的更好;
- [] 或 test 做不到的,[[ ]] 还能做到。
2.1 [[ ]] 支持字符串、整数比较运算 和 逻辑运算
2.1.1 在bash中
[cs ~]$ s1='a';s2='b';s3='a'
[cs ~]$ [ $s1 = $s2 || $s1 = $s3 ]
bash: [: missing `]'
bash: a: command not found
[cs ~]$ [[ $s1 = $s2 || $s1 = $s3 ]]
[cs ~]$ echo $?
0
[cs ~]$ [[ $s1 = $s2 -o $s1 = $s3 ]]
bash: syntax error in conditional expression
bash: syntax error near `-o'
[cs ~]$ [ $s1 = $s2 && $s1 = $s3 ]
bash: [: missing `]'
[cs ~]$ [[ $s1 = $s2 && $s1 = $s3 ]]
[cs~]$ echo $?
1
[cs ~]$ [[ $s1 = $s2 -a $s1 = $s3 ]]
bash: syntax error in conditional expression
bash: syntax error near `-a'
2.1.2 在zsh中
cs @ edu zsh $ s1='a';s2='b';s3='a'
cs @ edu zsh $ [ $s1 = $s2 || $s1 = $s3 ]
[: ']' expected
zsh: command not found: a
cs @ edu zsh $ [[ $s1 = $s2 || $s1 = $s3 ]]
cs @ edu zsh $ echo $?
0
cs @ edu zsh $ [[ $s1 = $s2 -o $s1 = $s3 ]]
zsh: condition expected: $s1
cs @ edu zsh $ [ $s1 = $s2 && $s1 = $s3 ]
[: ']' expected
cs @ edu zsh $ [[ $s1 = $s2 && $s1 = $s3 ]]
cs @ edu zsh $ echo $?
1
cs @ edu zsh $ [[ $s1 = $s2 -a $s1 = $s3 ]]
zsh: condition expected: $s1
在 [[ ]] 中支持使用 && 和 ||,不支持 -o 和 -a。
2.2 支持正则表达式
在 Shell [[ ]] 中,可以使用=~来检测字符串是否符合某个正则表达式,其用法为:
[[ 字符串 =~ 正则表达式 ]]
例如:
- ^[0-9]*$ 是检测是否为纯数字字符串的正则表达式
- ^[a-z]*$ 是检测是否为纯小写字母字符串的正则表达式
2.2.1 在bash中
[cs ~]$ s="12345"; [[ $s =~ ^[0-9]*$ ]]; echo $?
0
[cs ~]$ s="12345abc"; [[ $s =~ ^[0-9]*$ ]]; echo $?
1
[cs ~]$ s="12345"; [[ $s =~ ^[a-z]*$ ]]; echo $?
1
[cs ~]$ s="abc"; [[ $s =~ ^[a-z]*$ ]]; echo $?
0
2.2.2 在zsh中
cs @ edu zsh $ s="12345"; [[ $s =~ ^[0-9]*$ ]]; echo $?
0
cs @ edu zsh $ s="12345abc"; [[ $s =~ ^[0-9]*$ ]]; echo $?
1
cs @ edu zsh $ s="12345"; [[ $s =~ ^[a-z]*$ ]]; echo $?
1
cs @ edu zsh $ s="abc"; [[ $s =~ ^[a-z]*$ ]]; echo $?
0
2.2.3 注意
为了确保[[]]取得正确结果,其中的变量名要加上$前缀。
在bash中:
[cs ~]$ s="12345"; [[ s =~ ^[0-9]*$ ]]; echo $?
1
[cs ~]$ s="12345"; [[ $s =~ ^[0-9]*$ ]]; echo $?
0
[cs ~]$ s="abc"; [[ s =~ ^[0-9]*$ ]]; echo $?
1
[cs ~]$ s="abc"; [[ $s =~ ^[0-9]*$ ]]; echo $?
1
[cs ~]$ s="abc"; [[ s =~ ^[a-z]*$ ]]; echo $?
0
[cs ~]$ s="abc"; [[ $s =~ ^[a-z]*$ ]]; echo $?
0
[cs ~]$ s="123"; [[ s =~ ^[a-z]*$ ]]; echo $?
0
[cs ~]$ s="123"; [[ $s =~ ^[a-z]*$ ]]; echo $?
1