我正在阅读有关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
有什么区别?
Answers:
单个[]
是posix shell兼容条件测试。
Double [[]]
是对标准的扩展,[]
并由bash和其他shell(例如zsh,ksh)支持。它们支持额外的操作(以及标准的posix操作)。例如:||
代替和-o
与regex匹配=~
。在条件构造的bash手册部分中可以找到更完整的差异列表。
使用[]
时,你想要你的脚本是跨弹便携。使用[[]]
,如果你想不被支持的条件表达式[]
,不需要是便携式的。
[[ ]]
(例如,使用bash #!/bin/bash
或#!/usr/bin/env bash
),则应使用Portable选项。假定/ bin / sh支持此类扩展的脚本将在诸如Debian和Ubuntu等最新发行版的操作系统上中断,而实际情况并非如此。
行为差异
在Bash 4.3.11中测试:
POSIX vs Bash扩展:
[
是POSIX[[
是Bash扩展¹¹,网址为:https : //www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs常规命令与魔术
[
只是一个带有奇怪名称的常规命令。
]
只是其中的一个论点,[
因此无法使用进一步的论点。
Ubuntu 16.04实际上/usr/bin/[
由coreutils提供了一个可执行文件,但bash内置版本优先。
Bash解析命令的方式没有任何改变。
特别<
是重定向,&&
并||
连接多个命令,( )
除非通过进行转义\
,否则将生成子外壳,并且单词扩展照常发生。
[[ X ]]
是一个X
可以神奇地解析的单一构造。<
,&&
,||
并()
经特殊处理,以及分词规则是不同的。
还有进一步的差异,例如=
和=~
。
在Bashese中:[
是一个内置命令,并且[[
是一个关键字:https : //askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]
:字典比较[ a \< b ]
:与上述相同。\
必需,否则像其他任何命令一样进行重定向。重击扩展。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? ]]
:是的,因为它确实进行模式匹配(* ? [
很神奇)。不会将glob扩展到当前目录中的文件。[ ab = a? ]
:a?
glob扩展。根据当前目录中的文件,可能是true还是false。[ ab = a\? ]
:错误,不是全局扩展=
而==
在双方的同[
和[[
,不过==
是一个bash扩展。case ab in (a?) echo match; esac
:POSIX等效[[ ab =~ 'ab?' ]]
:错误4,失去魔法''
[[ 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等效项。
如果您使用[[ ]]
:
[
只是一个带有奇怪名称的常规命令,不涉及任何特殊的语义。¹源自[[...]]
Korn外壳中的等效构造
²,但对于a
or的某些值b
(例如+
或index
)失败,并且如果a
and b
看起来像十进制整数,则进行数字比较。expr "x$a" '<' "x$b"
都可以解决。
³也失败了的一些值a
或b
喜欢!
或(
。
在bash 3.2及更高版本中为4,并且未提供与bash 3.1的兼容性(与一样BASH_COMPAT=3.1
)
5,尽管分组(此处使用{...;}
命令组而不是(...)
运行不必要的子shell)不是必需的,因为||
and &&
壳运算符(与||
and &&
[[...]]
运算符或-o
/ -a
[
运算符相对)具有相同的优先级。因此[ a = a ] || [ a = b ] && [ a = b ]
将是等效的。
[]
应该理解为我的偏好:[]
如果您不想失去便携性则使用。如前所述这里:如果便携/ POSIX一致性或BourneShell是一个问题,应使用旧的语法。另一方面,如果脚本需要BASH,Zsh或KornShell,则新语法通常更灵活,但不一定向后兼容。我宁愿去,[[ ab =~ ab? ]]
如果我可以并且不关心向后兼容性,那就比printf 'ab' | grep -Eq 'ab?'
在用于状态测试的单括号内(即[...]),=
所有shell都支持某些运算符,例如single ,而==
某些较早的Shell不支持使用operator 。
里面的条件测试(即[[...]])双括号,有使用没有任何区别=
或==
旧或新的炮弹。
编辑:我还应该注意:在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编写,否则建议使用[[
。
您可以将双方括号用于正则表达式匹配,例如:
if [[ $1 =~ "foo.*bar" ]] ; then
(只要您使用的bash版本支持此语法)