rkm*_*max 142 bash if-statement
我正在阅读bash示例,if
但有些示例是用单个方括号编写的:
if [ -f $param ]
then
#...
fi
Run Code Online (Sandbox Code Playgroud)
其他双方括号:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Run Code Online (Sandbox Code Playgroud)
有什么不同?
cmh*_*cmh 166
单个[]
是posix shell兼容条件测试.
Double [[]]
是标准的扩展,[]
由bash和其他shell支持(例如zsh,ksh).它们支持额外的操作(以及标准的posix操作).例如:||
代替-o
和正则表达式匹配=~
.在条件结构的bash手册部分中可以找到更完整的差异列表.
[]
只要您希望脚本可以跨shell移植,就可以使用它.使用[[]]
,如果你想不被支持的条件表达式[]
,并不需要移植.
Cir*_*四事件 74
行为差异
在Bash 4.3.11中测试过:
POSIX vs Bash扩展:
[
是POSIX[[
是一个Bash扩展¹记录在:https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs常规命令vs魔法
[
只是一个带有奇怪名称的常规命令.
]
只是一个参数,[
可以防止使用更多的参数.
Ubuntu 16.04实际上有一个/usr/bin/[
coreutils提供的可执行文件,但bash内置版本优先.
Bash解析命令的方式没有任何改变.
具体地讲,<
是重定向,&&
以及||
连接多个命令,( )
生成子shell除非逃脱\
,和字膨胀发生如常.
[[ X ]]
是一个X
神奇地解析的单一构造.<
,&&
,||
并()
经特殊处理,以及分词规则是不同的.
还有其他差异,如=
和=~
.
在Bashese:[
是一个内置命令,[[
是一个关键字:https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]
:词典比较[ a \< b ]
:与上面相同.\
需要或者像任何其他命令一样重定向.Bash扩展.expr a \< b > /dev/null
:POSIX等效²,请参阅:如何在Bash中测试字典小于或等于的字典?&&
和 ||
[[ a = a && b = b ]]
:真实,逻辑和[ a = a && b = b ]
:语法错误,&&
解析为AND命令分隔符cmd1 && cmd2
[ a = a -a b = b ]
:等效,但由POSIX³弃用[ a = a ] && [ b = b ]
:POSIX和可靠的等价物(
[[ (a = a || a = b) && a = b ]]
:假的[ ( a = a ) ]
:语法错误,()
被解释为子shell[ \( a = a -o a = b \) -a a = b ]
:等价,但()
POSIX弃用{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX等价5扩展时的单词拆分和文件名生成(split + glob)
x='a b'; [[ $x = 'a b' ]]
:是的,不需要报价x='a b'; [ $x = 'a b' ]
:语法错误,扩展为 [ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
:如果当前目录中有多个文件,则出现语法错误.x='a b'; [ "$x" = 'a b' ]
:POSIX等价物=
[[ ab = a? ]]
:true,因为它确实模式匹配(* ? [
很神奇).不会将glob扩展为当前目录中的文件.[ ab = a? ]
:a?
glob扩展.因此可能是真或假,具体取决于当前目录中的文件.[ ab = a\? ]
:false,不是glob扩展=
而==
在双方的同[
和[[
,不过==
是一个bash扩展.case ab in (a?) echo match; esac
:POSIX等价物[[ ab =~ 'ab?' ]]
:假4,失去魔力''
[[ ab? =~ 'ab?' ]]
:是的=~
[[ ab =~ ab? ]]
:true,POSIX 扩展正则表达式匹配,?
不进行glob扩展[ a =~ a ]
:语法错误.没有bash等价物.printf 'ab\n' | grep -Eq 'ab?'
:POSIX等价物(仅限单行数据)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
:POSIX等价物.建议:始终使用[]
.
对于[[ ]]
我见过的每个构造,都有POSIX等价物.
如果您使用[[ ]]
:
[
它只是一个带有奇怪名称的常规命令,不涉及特殊的语义.¹灵感来自[[...]]
Korn shell中的等效构造
²但是对于某些值a
或b
(例如+
或index
)失败,并进行数字比较,如果a
它b
看起来像十进制整数.expr "x$a" '<' "x$b"
适用于两者.
³并且也失败了某些a
或b
类似的值!
或(
.
4在bash 3.2及以上版本中提供与bash 3.1的兼容性未启用(如同BASH_COMPAT=3.1
)
5尽管分组(这里与{...;}
命令组,而不是(...)
这将运行一个不必要的子shell)不是必要的,因为||
和&&
壳运营商(而不是在||
与&&
[[...]]
运营商或-o
/ -a
[
经营者)具有相同的优先级.所以[ a = a ] || [ a = b ] && [ a = b ]
相同.
sam*_*hen 14
在用于条件测试的单个括号内(即[...]),=
所有shell都支持某些运算符(如single ),而==
某些较旧的shell不支持使用运算符.
对于内部条件测试双括号(即[[...]]),存在使用没有任何区别=
或==
旧或新的炮弹.
编辑:我还应该注意:在bash中,如果可能的话,总是使用双括号[[...]],因为它比单个括号更安全.我将通过以下示例说明原因:
if [ $var == "hello" ]; then
Run Code Online (Sandbox Code Playgroud)
如果$ var恰好是null/empty,那么这就是脚本看到的内容:
if [ == "hello" ]; then
Run Code Online (Sandbox Code Playgroud)
这将打破你的脚本.解决方案是使用双括号,或者始终记住在变量("$var"
)周围加上引号.双括号是更好的防御性编码实践.
Gil*_*not 11
[[
是一个类似于(但比[
命令更强大)的bash关键字.
看到
http://mywiki.wooledge.org/BashFAQ/031和http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
除非你是为POSIX sh写的,否则我们建议你[[
.
[
是一个builtin
类似 printf 的东西。Bash 语法期望在与命令相同的位置看到它。对于 Bash 来说,除了内置]
函数所期望的这一事实之外,什么都不是[
。(man bash / shell 内置命令)[[
是一个keyword
“如果”。Bash 语法也期望它在与命令相同的位置开始,但它不是执行它,而是进入条件上下文。并且]]
也是结束此上下文的关键字。(man bash / SHELL 语法 / 复合命令)按顺序,bash 尝试解析:语法关键字 > 用户别名 > 内置函数 > 用户函数 > $PATH 中的命令
type [ # [ is a shell builtin
type [[ # [[ is a shell keyword
type ] # bash: type: ]: not found
type ]] # ]] is a shell keyword
compgen -k # Keywords: if then else ...
compgen -b # Builtins: . : [ alias bg bind ...
which [ # /usr/bin/[
Run Code Online (Sandbox Code Playgroud)
[
我猜它会执行更多的解析代码。但我知道它调用相同数量的系统调用(用[[
在语法上,即使对于人类来说也更容易解析,因为它启动了一个上下文。对于算术条件,请考虑使用((
.time for i in {1..1000000}; do [ 'a' = 'b' ] ; done # 1.990s
time for i in {1..1000000}; do [[ 'a' == 'b' ]] ; done # 1.371s
time for i in {1..1000000}; do if [ 'a' = 'a' ]; then if [ 'a' = 'b' ];then :; fi; fi ; done # 3.512s
time for i in {1..1000000}; do if [[ 'a' == 'a' ]]; then if [[ 'a' == 'b' ]];then :; fi; fi; done # 2.143s
strace -cf bash -c "for i in {1..100000}; do if [ 'a' = 'a' ]; then if [ 'a' = 'b' ];then :; fi; fi ; done;" # 399
strace -cf bash -c "for i in {1..100000}; do if [[ 'a' == 'a' ]]; then if [[ 'a' == 'b' ]];then :; fi; fi ; done;" # 399
Run Code Online (Sandbox Code Playgroud)
我建议使用[[
:如果您不明确关心 posix 兼容性,则意味着您不关心,因此不必关心如何使不兼容的脚本“更”兼容。