我只是想知道两者之间到底有什么区别
[[ $STRING != foo ]]
和
[ $STRING != foo ]
除了后者是posix兼容的以外,在sh中找到,而前者是在bash中找到的扩展。
我只是想知道两者之间到底有什么区别
[[ $STRING != foo ]]
和
[ $STRING != foo ]
除了后者是posix兼容的以外,在sh中找到,而前者是在bash中找到的扩展。
Answers:
有几个区别。我认为最重要的几个是:
[是Bash和许多其他现代shell中的内置函数。内置[函数类似于test关闭的附加要求]。在内建[和test模仿的功能/bin/[,并/bin/test与他们一起的局限性,使脚本会向后兼容。最初的可执行文件仍然存在,主要是为了满足POSIX和向后兼容。type [在Bash中运行命令表示[默认情况下将其解释为内置命令。(注意:which [仅在PATH上查找可执行文件,等效于type -p [)[[不那么兼容,它不一定适用于任何/bin/sh指向的地方。所以[[是更现代的Bash /岩组/ KSH选项。[[是内置在shell中的,并且没有旧的要求,所以您不必担心基于IFS变量的单词拆分,从而使评估为带空格的字符串的变量变得混乱。因此,您实际上不需要将变量放在双引号中。在大多数情况下,其余只是一些更好的语法。要查看更多差异,我建议将此链接链接至常见问题解答:test,[和[[有什么区别?。实际上,如果您认真对待bash脚本,建议您阅读整个Wiki,包括FAQ,Pitfalls和Guide。 指南部分的测试部分也解释了这些差异,以及为什么在[[您不必担心便携性时作者认为更好的选择。主要原因是:
< >使用反斜杠将其转义为小于和大于,以免它们被评估为输入重定向,这实际上可能会由于覆盖文件而使某些内容混乱。这又回到[[了内置函数。如果[(test)是一个外部程序,则外壳程序必须在其评估方式上<并且>仅在/bin/test被调用时才例外,这实际上没有任何意义。简而言之:
[是内置的bash
[[]]是bash 关键字
关键字:关键字与内置函数很像,但是主要区别在于特殊的解析规则适用于它们。例如,[是bash内置函数,而[[是bash关键字。它们都用于测试内容,但是由于[[是关键字而不是内置函数,因此它受益于一些特殊的解析规则,这些规则使其变得更加容易:
$ [ a < b ]
-bash: b: No such file or directory
$ [[ a < b ]]
第一个示例返回错误,因为bash尝试将文件b重定向到命令[a]。第二个示例实际上完成了您期望的操作。字符<不再具有文件重定向运算符的特殊含义。
资料来源:http : //mywiki.wooledge.org/BashGuide/CommandsAndArguments
[是POSIX shell命令;它 ]仅是该命令要查找的参数,因此语法是平衡的。该命令是的同义词,test除了test不查找结束符]。
行为差异
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等效²,请参见:https : //stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&& 和 ||
[[ 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外壳中的等效构造
²,但对于aor的某些值b(例如+或index)失败,并且如果a和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 ]将是等效的。
printf 'ab' | grep -Eq 'ab?'范围内if [ … ]?
if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi。[]是一样的命令grep。该()可能不需要对命令我不知道:我添加这因为|,取决于猛砸如何解析的事情。如果没有,|我相信你可以写if cmd arg arg; then。
()看来:stackoverflow.com/questions/8965509/...
单个括号,即[]POSIX shell兼容以包含条件表达式。
双括号,即[[]]是标准POSIX版本的增强(或扩展)版本,bash和其他shell(zsh,ksh)支持。
在bash中,为我们使用数值比较eq,ne,lt和gt,用双括号进行比较,我们可以使用==,!=,<,和>字面。
[是测试命令的同义词。即使将其内置到外壳中,它也会创建一个新进程。[[ 是它的新改进版本,它是关键字,而不是程序。 例如:
[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works
if声明的上下文中,请参见mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D