一位同事最近在一次代码评审中声称,在类似于

if [ "`id -nu`" = "$someuser" ] ; then
     echo "I love you madly, $someuser"
fi

他无法提供理由。有吗?


当前回答

行为差异

Bash 4.3.11的一些差异:

POSIX vs Bash扩展:[是POSIX[[是灵感来自KornShell的Bash扩展常规命令vs魔术[只是一个名称奇怪的常规命令。]只是[的最后一个论点。Ubuntu 16.04实际上在/usr/bin/[由coreutils提供,但Bash内置版本优先。Bash解析命令的方式没有任何改变。特别是,<是重定向,&&和||连接多个命令,()生成子shell,除非被\转义,单词扩展照常发生。[[X]]是一个可以神奇地解析X的构造。<,&&,||和()被特殊处理,并且分词规则不同。还有更多的差异,如=和=~。在巴语中:[是一个内置命令,[[是一个关键字:shell内置命令和shell关键字有什么区别?<[[a<b]]:词典比较[a\<b]:同上。\必需,否则会像任何其他命令一样进行重定向。Bash扩展。expr x“$x”\<x“$y”>/dev/null或[“$(expr x”$x“\<x”$y“)”=1]:POSIX等价物,请参阅:如何在Bash中测试字符串的字典小于或等于?&&以及||[[a=a&&b=b]]:真、逻辑和[a=a&&b=b]:语法错误,&&解析为AND命令分隔符cmd1&&cmd2[a=a]&&[b=b]:POSIX可靠等效[a=a-ab=b]:几乎等同,但POSIX不赞成,因为它是疯狂的,并且对于a或b之类的某些值失败!或(这将被解释为逻辑运算([[(a=a||a=b)&&a=b]]:假。如果没有(),则为真,因为[[&&]]的优先级高于[[||]][(a=a)]:语法错误,()被解释为子shell[\(a=a-o a=b\)-a a=b]:等效,但POSIX不推荐使用()、-a和-o。如果没有\(\),则为真,因为-a的优先级高于-o{[a=a]||[a=b];}&&[a=b]POSIX等价物,未弃用。然而,在这种特殊情况下,我们可以只写:[a=a]||[a=b]&&[a=b],因为||和&&shell运算符具有相同的优先级,而不是[[||]]和[[&&]]以及-o、-a和-o[扩展时的分词和文件名生成(split+glob)x=“b”;[[$x=“a b”]]:真。不需要报价x=“b”;[$x=“a b”]:语法错误。它扩展到[a b='a b']x=“*”;[$x=“a b”]:如果当前目录中有多个文件,则出现语法错误。x=“b”;[“$x”=“a b”]:POSIX等效=[[ab=a?]]:true,因为它进行模式匹配(*?[很神奇)。glob不会扩展到当前目录中的文件。[ab=a?]:a?glob扩展。因此,根据当前目录中的文件,它可能为真或假。[ab=a\?]:false,不是glob扩展=和==在[和[[中都相同,但==是Bash扩展。(a?)回波匹配中的情况ab;esac:POSIX等效[[ab=~'ab?']]:false,在Bash 3.2及更高版本中失去与“”的魔力,并且未启用与Bash 3.1的兼容性(如Bash_COMPAT=3.1)[[ab?=~'ab?']]:真=~[[ab=~ab?]]:真。POSIX扩展正则表达式匹配和?不进行glob扩展[a=~a]:语法错误。没有Bash等效项。printf“ab \n”| grep-等式“ab?”:POSIX等效(仅单行数据)awk“BEGIN{exit!(ARGV[1]~ ARGV[2])}”ab“ab?”:POSIX同等产品。

建议:始终使用[]

我见过的每个[[]]构造都有POSIX等价物。

如果使用[[]],则:

失去便携性迫使读者学习另一个Bash扩展的复杂性。[只是一个具有奇怪名称的常规命令,不涉及特殊语义。

感谢Stéphane Chazelas的重要更正和补充。

其他回答

无法使用[[的典型情况是在autotools configure.ac脚本中。括号具有特殊和不同的含义,因此必须使用test而不是[[或[[--请注意,test和[是同一个程序。

[[]]有更多功能-我建议您查看《高级Bash脚本指南》以了解更多信息,特别是第7章中的扩展测试命令部分。测验。

顺便说一下,正如指南所指出的,[[]]是在ksh88(1988年版的KornShell)中引入的。

哪个比较器、测试、括号或双括号最快?:

双括号是“复合”命令“where as test and the single支架是外壳内置的(和现实是相同的命令)。因此单支架和双支架执行不同的代码。测试和单个支架是最便携的单独和外部命令。但是,如果您远程使用现代版BASH,双人支架得到支撑。

行为差异

Bash 4.3.11的一些差异:

POSIX vs Bash扩展:[是POSIX[[是灵感来自KornShell的Bash扩展常规命令vs魔术[只是一个名称奇怪的常规命令。]只是[的最后一个论点。Ubuntu 16.04实际上在/usr/bin/[由coreutils提供,但Bash内置版本优先。Bash解析命令的方式没有任何改变。特别是,<是重定向,&&和||连接多个命令,()生成子shell,除非被\转义,单词扩展照常发生。[[X]]是一个可以神奇地解析X的构造。<,&&,||和()被特殊处理,并且分词规则不同。还有更多的差异,如=和=~。在巴语中:[是一个内置命令,[[是一个关键字:shell内置命令和shell关键字有什么区别?<[[a<b]]:词典比较[a\<b]:同上。\必需,否则会像任何其他命令一样进行重定向。Bash扩展。expr x“$x”\<x“$y”>/dev/null或[“$(expr x”$x“\<x”$y“)”=1]:POSIX等价物,请参阅:如何在Bash中测试字符串的字典小于或等于?&&以及||[[a=a&&b=b]]:真、逻辑和[a=a&&b=b]:语法错误,&&解析为AND命令分隔符cmd1&&cmd2[a=a]&&[b=b]:POSIX可靠等效[a=a-ab=b]:几乎等同,但POSIX不赞成,因为它是疯狂的,并且对于a或b之类的某些值失败!或(这将被解释为逻辑运算([[(a=a||a=b)&&a=b]]:假。如果没有(),则为真,因为[[&&]]的优先级高于[[||]][(a=a)]:语法错误,()被解释为子shell[\(a=a-o a=b\)-a a=b]:等效,但POSIX不推荐使用()、-a和-o。如果没有\(\),则为真,因为-a的优先级高于-o{[a=a]||[a=b];}&&[a=b]POSIX等价物,未弃用。然而,在这种特殊情况下,我们可以只写:[a=a]||[a=b]&&[a=b],因为||和&&shell运算符具有相同的优先级,而不是[[||]]和[[&&]]以及-o、-a和-o[扩展时的分词和文件名生成(split+glob)x=“b”;[[$x=“a b”]]:真。不需要报价x=“b”;[$x=“a b”]:语法错误。它扩展到[a b='a b']x=“*”;[$x=“a b”]:如果当前目录中有多个文件,则出现语法错误。x=“b”;[“$x”=“a b”]:POSIX等效=[[ab=a?]]:true,因为它进行模式匹配(*?[很神奇)。glob不会扩展到当前目录中的文件。[ab=a?]:a?glob扩展。因此,根据当前目录中的文件,它可能为真或假。[ab=a\?]:false,不是glob扩展=和==在[和[[中都相同,但==是Bash扩展。(a?)回波匹配中的情况ab;esac:POSIX等效[[ab=~'ab?']]:false,在Bash 3.2及更高版本中失去与“”的魔力,并且未启用与Bash 3.1的兼容性(如Bash_COMPAT=3.1)[[ab?=~'ab?']]:真=~[[ab=~ab?]]:真。POSIX扩展正则表达式匹配和?不进行glob扩展[a=~a]:语法错误。没有Bash等效项。printf“ab \n”| grep-等式“ab?”:POSIX等效(仅单行数据)awk“BEGIN{exit!(ARGV[1]~ ARGV[2])}”ab“ab?”:POSIX同等产品。

建议:始终使用[]

我见过的每个[[]]构造都有POSIX等价物。

如果使用[[]],则:

失去便携性迫使读者学习另一个Bash扩展的复杂性。[只是一个具有奇怪名称的常规命令,不涉及特殊语义。

感谢Stéphane Chazelas的重要更正和补充。

我感到惊讶的是,我没有看到这个问题提前提出,但请考虑:

$ n=5
$ [[ $n -gt 0 ]] && echo $n is positive
5 is positive
$ n=foo
$ [[ $n -gt 0 ]] && echo $n is positive
$ [ "$n" -gt 0 ] && echo $n is positive
bash: [: foo: integer expression expected

行[[$n-gt 0]]中缺少错误消息,导致[[完全不可用。也许我太苛刻了,正确的答案是避免在[[中进行整数比较,但我强烈建议不要使用[[。