我正在阅读 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 b
like !
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
, -a
and[
扩展时的分词和文件名生成 (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,否则我们建议使用[[
.
[
类似于builtin
printf。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 版本支持此语法)