在 Shell 语言中,经常会看到中括号和括号组成的特殊标识,例如:[]
、[[]]
、(())
、$(())
、()
。这些符号经常使我们非常迷惑,弄清楚它们之间的作用和区别非常必要。
在开始之前,我们先来学习一个 test 命令。
test命令
test 命令主要是用来做表达式的判断,其语法结构如下:
test {EXPRESSION}
例如:
if test "a" == "a"
then
echo match!
fi
[]
其实 [] 符号的作用与 test 命令一样,都用于判断表达式的真假。只不过 [] 将表达式括起来了,更加易读。上面的例子用 [] 重写就会变成这样:
if [ "a" == "a" ]
then
echo match!
fi
让我们来看一个更加复杂点的例子:
a=12
if [ $a -gt 10 -a $a -lt 15 ]
then
echo match!
fi
[[]]
[[]]
符号与 []
符号的区别是,在 [[]]
符号里,我们引用变量时可以不再用 $ 符号了,而且还可以使用 && 和 || 运算符。
像上面判断变量 a 的范围,我们在 []
符号中,只能使用 -gt
、-a
、-lt
等操作符。但如果用[[]]
实现,我们就可以用上&&
和||
操作符:
a=12
if [[ a -gt 10 && a -lt 15 ]]
then
echo match!
fi
但你会发现我们做算术比较还需要写-lt
、-gt
之类的东西,非常恶心。那么我们可以用下面这个符号。
let 命令
我们在进行算术运算时,我们可以使用 let 命令进行运算:
a=10
let b=a+10
echo $b
在 let 命令中的变量,不需要使用 $ 符号就可以使用。像上面的 a 变量,其实一个变量,但是在第 2 行的 let 语句不需要使用 $ 符号也能成功运算。
(())
这组符号的作用与 let 指令相似,用在算数运算上,是 bash 的内建功能。所以,在执行效率上会比使用 let指令要好许多。
在这个符号里,我们可以进行整数运算,它的作用和 let 命令一样。
a=10
(( b = a + 10 ))
echo $b
或者我们可以将计算结果作为表达式,如果结果是 0 表示假,其余全部是真。
a=10
if (( a + 10 ))
then
echo true
fi
又或者是:
a=10
if (( a <= 12 && a > 0))
then
echo great than 10
fi
$(())
这玩意和上面的差不多,但是不会像命令一样有返回值,而是会像变量一样把运算结果替换出来。例如:
a=10
b=$(( a <= 12 && a > 0))
echo $b
输出:1
。
a=10
b=$(( a <= 12 && a < 0))
echo $b
输出:0
。
因此如果要让它作为一个表达式的话,就要结合 []
符号。例如:
a=10
if [ $(( a <= 12 && a > 0)) -eq 1 ]
then
echo great than 10
fi
对于 (())
符号而言只有 bash 这个 Shell 有,而 $(())
则是所有 Shell 都有,更为通用。
()
()
符号表示括号中作为一个子 Shell 运行,运行结果不干扰外层的 Shell。
看看下面这个例子:
a=2
(a=1)
echo $a
输出是:2
。
因为括号括起来是一个子 Shell,不影响外层 Shell 的运行,所以对 a 赋值为 1 不影响外层结果,外层的 a 变量还是 2。
利用上面子 Shell 这个特性,我们在写 Shell 脚本的时候可以做到不切换当前目录而在其他目录干点事儿。例如:
(cd hello; echo "Hello Shell" > hello.txt); pwd; cat hello/hello.txt
上面我进入了子目录 hello,并创建了一个 hello.txt 文件。输出结果是:
/Users/yurongchan/Yosemite/shell-practice/practice
Hello Shell
可以看到我当前目录没有改变,但是文件已经创建成功了。
{ } 大括号 (Block of code)
这种用法与上面介绍的指令群组非常相似,但有个不同点,它在当前的 shell 执行,不会产生 subshell。 单纯只使用大括号时,作用就像是个没有指定名称的函数一般。
a=2
{ a=1; }
echo $a
上面输出:1
。
- 大括号
{}
里的运算是在当前 Shell 运行,会影响外层结果,而括号()
的不会。 - 大括号里最后一个语句必须要用
;
分号结束,否则出错,而括号()
的并没有这个要求。