bash中的小括号以及双中括号,双小括号详解

单个小括号在 bash 中不像其它语言那样表示分隔符和优先级调整,而是启动一个 subshell 来执行里面的代码,也就是再启动一个 bash 来运行,好处是 subshell 有独立的环境变量。

例如,你在 home 目录,cd 到 /tmp 目录,sleep 5 秒,最后 cd 回 home,但是你会在 sleep 的过程中按 Ctrl + c 中断。

如果你使用这个命令:

~$ cd /tmp/; sleep 5; cd ~
^C
/tmp$

你会留在 /tmp 目录中,因为最后的 cd ~ 根本没执行。所以如果你希望临时切换别的目录执行某些命令,但又希望中断后回到原来的目录,这个方法就不凑效了。

但是如果你加上小括号:

~$ ( cd /tmp/; sleep 5; )
^C
~$

这里没有最后的 cd ~,因为多此一举,subshell 有自己的工作目录,相当于你另外开一个终端而已,这样避免一些环境变量被某些代码弄乱。

$ [ 3 \> 10 ]; echo $?
0

因为这不是按数字比较,而是按字符串,这里 3 和 10 在 bash 眼中就是字符串,传给 test 后,test 默认也是当成字符串。

如果显式加上单引号,就清楚了:

$ [ '3' \> '10' ]; echo $?
0

字符串比较就是按 ASCII 编码比较,因为先比较第一个字符,3 比 1 的 ASCII 编码大。

所以上面的几个比较其实全部都是字符串比较,只不过长度一样的话,看起来就是按数字比较。

如果想按数字大小怎么办?可以用 -gt 参数,这样 test 就会把两边当成一个数字看待:

$ [ 3 -gt 1 ]; echo $?
0
$ [ 3 -gt 6 ]; echo $?
1
$ [ 3 -gt 10 ]; echo $?
1

同样,-eq 也是按数字比较:

$ [ 1 == 01 ]; echo $?;
1
$ [ 1 -eq 01 ]; echo $?;
0

复合条件

假如你要再判断某个目录是否存在,又想当然写成:

$ [ -f exists.txt && -d exists_folder ]; echo $?
bash: [: missing `]'
2

结果提示漏了右括号,那是因为 && 被 bash 预先解析了,而不是当成 test 的参数传递。

  • && 表示如果左边的命令正常执行了,那么继续执行右边的命令,相当于没有 else 部分的 if 语句简化版。

  • 而 || 表示如果左边的命令不是正常执行了,那么继续执行右边的命令,相当于没有 then 部分的 if 语句(或者 if not)。

从效果看也可以分别当成逻辑与和逻辑或的。

所以上面那条命令以 && 分开看,左边的 [ -f exists.txt 明显是个不完整命令,漏了个 ],当然右边的也漏了 [

修正如下:

$ [ -f exists.txt ] && [ -d exists_folder ]; echo $?
0

换回一般写法也应该是:

$ test -f exists.txt && test -d exists_folder; echo $?
0

双方括号关键词

上面我们用 [ -f exists.txt && -d exists_folder ] 来表示复合条件,结果发现这是一个坑,于是 bash 后来从 ksh 抄来一个特性来填这个坑,结果挖了更大的一个坑。

把单括号换成双括号就 OK 了:

$ [[ -f exists.txt && -d exists_folder ]]; echo $?
0

震惊之情溢于言表,&& 不是隔开两个命令么,怎么用两个方括号又合法了?

前面说说单方括号是语法糖,因为只是 test 命令的另一种写法,bash 最后会调用程序 test,一般就是 /usr/bin/test。

用 type 程序看下类型:

$ type [
[ is a shell builtin
$ type test
test is a shell builtin

又说这是叫 builtin,坑爹,不过常用命令如 cd、echo 都是这样的。

但是说双方括号是「关键词」,关键词就是 bash 自己内建的语法分析:

$ type [[
[[ is a shell keyword

就因为这是关键词,所以被双方括号包围的代码都有另外一种意义,&&||> 和 < 这些符号的意义都被改变了,就和其它编程语言的用法一样了。

例如上面的比较大小,对 > 不再需要转义了:

$ [[ 3 > 1 ]]; echo $?
0

但依然是表示按字符串比较,不是按数字:

$ [[ 3 > 10 ]]; echo $?
0

可以看作增强版的 test,因为逻辑与和逻辑或已经可以直接用 && 和 ||,所以 -a-o 就不能用了,其余的参数和 test 基本一样,-f 和 -d 也可以用。

还可以用 =~ 来检查是否匹配正则,简单的就不用劳烦 grep 了:

$ [[ abc =~ a ]]; echo $?
0

因为对 && 那几个符号自动转义了,比较直观,不容易搞错,相对安全,所以推荐优先使用 [[ 而不是 [

双小括号的作用

双小括号的作用就是把里面的代码作为算术表达式来执行,像双方括号一样,里面的代码有另外的意义。

例如给变量赋值:

$ a=1+1; echo $a
1+1
$ (( b = 1 + 1 )); echo $b
2

a 的 1+1 只是一个字符串,而 b 就是一个算术表达式结果。

正是因为是算术表达式,所以比较也是按数字本身而不是字符串:

$ (( 3 > 1 )); echo $?
0
$ (( 3 > 6 )); echo $?
1
$ (( 3 > 10 )); echo $?
1

所以也可以套上 if 语句来用。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值