我正在阅读 bash 示例,if但有些示例是用单方括号编写的:
if [ -f $param ]
then
#...
fi
其他带双方括号的:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
有什么不同?
我正在阅读 bash 示例,if但有些示例是用单方括号编写的:
if [ -f $param ]
then
#...
fi
其他带双方括号的:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
有什么不同?
Single[]是符合 posix shell 的条件测试。
Double[[]]是标准的扩展,[]并且受到 bash 和其他 shell(例如 zsh、ksh)的支持。它们支持额外的操作(以及标准的 posix 操作)。例如:||而不是-o和正则表达式匹配=~。更完整的差异列表可以在bash 手册的条件结构部分中找到。
[]每当您希望脚本可跨 shell 移植时使用。[[]]如果您想要不支持[]且不需要可移植的条件表达式,请使用此选项。
行为差异
在 Bash 4.3.11 中测试:
POSIX 与 Bash 扩展:
常规命令与魔法
[只是一个带有奇怪名称的常规命令。
]只是 的最后一个参数[。
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 ]: 同上。\required 或者像任何其他命令一样进行重定向。Bash 扩展。expr x"$x" \< x"$y" > /dev/null或[ "$(expr x"$x" \< x"$y")" = 1 ]:POSIX 等价物,请参阅:How to test strings for lexicographic less than or equal in Bash?&&和||
[[ a = a && b = b ]]: 真实的,合乎逻辑的[ a = a && b = b ]: 语法错误,&&解析为 AND 命令分隔符cmd1 && cmd2[ a = a ] && [ b = b ]: POSIX 可靠等价物[ a = a -a b = b ]a: 几乎等价,但被 POSIX 弃用,因为它是疯狂的,并且对于or blike !or的某些值会失败,或者(将被解释为逻辑操作(
[[ (a = a || a = b) && a = b ]]: 错误的。没有( ), 会是真的,因为[[ && ]]它的优先级高于[[ || ]][ ( a = a ) ]: 语法错误,()被解释为子shell[ \( a = a -o a = b \) -a a = b ]: 等效,但是(), -a, 和-o被 POSIX 弃用。没有\( \)会是真的,因为-a优先级高于-o{ [ a = a ] || [ a = b ]; } && [ a = b ]不推荐使用的 POSIX 等效项。然而,在这种特殊情况下,我们可以写成:[ a = a ] || [ a = b ] && [ a = b ]因为||和&&shell 运算符具有相同的优先级,不像[[ || ]]and[[ && ]]和-o, -aand[扩展时的分词和文件名生成 (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? ]]:是的,因为它会进行模式匹配(* ? [很神奇)。不 glob 扩展到当前目录中的文件。[ ab = a? ]: a?glob 扩展。所以可能是真或假,具体取决于当前目录中的文件。[ ab = a\? ]: false,不是全局扩展=and在and==中是相同的,但是是一个 Bash 扩展。[[[==case ab in (a?) echo match; esac: POSIX 等价物[[ ab =~ 'ab?' ]]: false,''在 Bash 3.2 及更高版本中失去魔力,并且未启用对 bash 3.1 的兼容性(如 with BASH_COMPAT=3.1)[[ ab? =~ 'ab?' ]]: 真的=~
[[ ab =~ ab? ]]: true,POSIX扩展正则表达式匹配,?不全局扩展[ a =~ a ]: 语法错误。没有 bash 等价物。printf 'ab\n' | grep -Eq 'ab?': POSIX 等效项(仅单行数据)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX 等价物。建议:一直使用[]
[[ ]]我见过的每个构造都有 POSIX 等价物。
如果你使用[[ ]]你:
[只是一个名称怪异的常规命令,不涉及特殊语义。感谢Stéphane Chazelas的重要更正和补充。
=在用于条件测试的单括号内(即 [ ... ]),所有 shell 都支持诸如 single 的一些运算符,而==一些较旧的 shell 不支持使用运算符。
在条件测试的双括号内(即 [[ ... ]]),在旧 shell 或新 shell 中使用=or没有区别。==
编辑:我还应该注意:在 bash 中,如果可能,请始终使用双括号 [[ ... ]],因为它比单括号更安全。我将通过以下示例说明原因:
if [ $var == "hello" ]; then
如果 $var 恰好为 null / 空,那么这就是脚本所看到的:
if [ == "hello" ]; then
这会破坏你的脚本。解决方案是使用双括号,或者始终记住在变量周围加上引号 ( "$var")。双括号是更好的防御性编码实践。
[[是一个与命令类似(但比[命令更强大)的 bash 关键字。
看
http://mywiki.wooledge.org/BashFAQ/031和http://mywiki.wooledge.org/BashGuide/TestsAndConditionals
除非您正在编写 POSIX sh,否则我们建议使用[[.
[类似于builtinprintf。Bash 语法期望在与命令相同的位置看到它。除了内置]函数期望它之外,这对 Bash 没有任何意义。[(man bash / SHELL BUILTIN 命令)[[是一个keyword如果。Bash 语法开始也期望它在与命令相同的位置,但不是执行它,而是进入条件上下文。并且]]也是结束此上下文的关键字。(man bash / SHELL GRAMMAR / 复合命令)按顺序,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/[
[较慢 <= 我猜它执行更多的解析代码。但我知道它调用了相同数量的系统调用(经过测试[[即使对于人类来说,它在语法上也更容易解析,因为它开始了一个上下文。对于算术条件,考虑使用((.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
我建议使用[[:如果您不明确关心 posix 兼容性,则意味着您不是,所以不要关心获得“更多”兼容的脚本不是。
您可以使用方括号进行轻度正则表达式匹配,例如:
if [[ $1 =~ "foo.*bar" ]] ; then
(只要您使用的 bash 版本支持此语法)