[[ $STRING != foo ]]
和
[ $STRING != foo ]
到底有什么区别,除了后者与posix兼容,在sh中找到,而前者是在bash中找到的扩展。
#1 楼
有几个区别。在我看来,一些最重要的是:[
是Bash和许多其他现代shell中的内置函数。内置的[
与test
相似,但另外需要关闭]
。内置[
和test
模仿了/bin/[
和/bin/test
的功能及其局限性,因此脚本将向后兼容。原始可执行文件仍然存在,主要是为了符合POSIX和向后兼容。在Bash中运行命令type [
表示默认情况下[
被解释为内置命令。 (注意:which [
仅在PATH上查找可执行文件,并且等效于type -p [
)。[[
不那么兼容,它不一定能与/bin/sh
指向的内容一起使用。所以[[
是更现代的Bash / Zsh / Ksh选项。因为
[[
内置在外壳中并且没有遗留要求,所以您不必担心基于IFS变量进行字分割的麻烦计算为带空格的字符串的变量。因此,您实际上不需要将变量放在双引号中。大多数情况下,其余的只是一些更好的语法。要查看更多差异,我建议将此链接链接到常见问题解答:test,[和[[?。实际上,如果您认真对待bash脚本,建议您阅读整个Wiki,包括FAQ,Pitfalls和Guide。指南部分的测试部分也解释了这些差异,以及为什么作者认为
[[
是更好的选择,如果您不必担心便携性的话。主要原因是:您不必担心引用测试的左侧,以便实际上将其读取为变量。
您不必用反斜杠转义小于和大于
< >
的值,以使它们不被评估为输入重定向,这实际上可能会由于覆盖文件而使某些内容混乱。再次回到[[
是内置的。如果[(test)是外部程序,则只有在调用<
的情况下,shell才必须以其评估>
和/bin/test
的方式产生异常,这实际上没有任何意义。评论
谢谢,指向bash FAQ的链接正是我想要的(不知道该页面,谢谢)。
– 0x89
09年8月9日在22:07
我使用此信息编辑了您的帖子,但是[和测试是作为内置函数执行的。内建函数旨在替换/ bin / [和/ bin / test,但也需要重现二进制文件的限制。命令'type ['验证是否使用了内置函数。 'which ['仅在PATH上搜索可执行文件,等效于'type -P ['
– klynch
2011年7月18日在22:55
#2 楼
简而言之:[是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不查找结尾处的]。
–卡兹
17-09-22在23:52
看到这里:pubs.opengroup.org/onlinepubs/009695399/utilities/test.html
–卡兹
17-09-22在23:53
#3 楼
行为差异Bash 4.3.11上的一些差异:
POSIX vs Bash扩展:
[
是POSIX [[
是Bash扩展¹,其记录在:https://www.gnu.org/software/bash/manual/bash.html#Conditional-构造常规命令与魔法
[
只是一个奇怪的常规命令名称。]
只是[
的一个参数,它防止使用其他参数。Ubuntu 16.04实际上在coreutils提供的
/usr/bin/[
处具有可执行文件,内置版本优先。Bash解析命令的方式不变。
特别地,
<
是重定向的,&&
和||
连接了多个命令,( )
除非通过\
进行转义,否则生成子壳,并且单词扩展照常进行。[[ X ]]
与使X
能够被神奇地解析的ingle构造。 <
,&&
,||
和()
经过特殊处理,并且分词规则不同。还有进一步的区别,例如
=
和=~
。内置命令,并且[
是关键字:https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword [[
<
:字典比较[[ a < b ]]
:与上述相同。 [ a \< b ]
是必需的,否则像其他任何命令一样进行重定向。 Bash扩展。\
:等效POSIX²,请参见:https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal- in-bash / 52707989#52707989 expr a \< b > /dev/null
和&&
||
:是的,逻辑和[[ a = a && b = b ]]
:语法错误,[ a = a && b = b ]
被解析为AND命令分隔符&&
:等价,但已被POSIX³弃用
cmd1 && cmd2
:POSIX和可靠的等价物[ a = a -a b = b ]
[ a = a ] && [ b = b ]
:假(
:语法错误,[[ (a = a || a = b) && a = b ]]
被解释为子shell [ ( a = a ) ]
:等效,但是POSIX不推荐使用()
[ \( a = a -o a = b \) -a a = b ]
POSIX等效5 分词和扩展名生成文件名(split + glob)
()
:true,不需要引号{ [ a = a ] || [ a = b ]; } && [ a = b ]
:语法错误,扩展为x='a b'; [[ $x = 'a b' ]]
x='a b'; [ $x = 'a b' ]
:如果当前目录中有多个文件,则语法错误。[ a b = 'a b' ]
:等效于POSIX的文件x='*'; [ $x = 'a b' ]
x='a b'; [ "$x" = 'a b' ]
:是的,因为它确实进行了模式匹配(=
很神奇)。不会将glob扩展到当前目录中的文件。[[ ab = a? ]]
:* ? [
glob会扩展。因此,根据当前目录中的文件,可能是true还是false。[ ab = a? ]
:false,不是全局扩展但是a?
是Bash扩展名。 [ ab = a\? ]
=
:正确,POSIX扩展正则表达式匹配,==
不全局扩展[
:语法错误。没有bash等效项。[[
:等效于POSIX(仅单行数据)==
:等效于POSIX。建议:始终使用
case ab in (a?) echo match; esac
。我见过的每个
[[ ab =~ 'ab?' ]]
构造都有POSIX等效项。如果使用
''
,您:便携性差
迫使读者学习另一个bash扩展的复杂性。
[[ ab? =~ 'ab?' ]]
只是一个具有奇怪名称的常规命令,不涉及任何特殊的语义。¹源自Korn shell中等效的
=~
构造²,但对于
[[ ab =~ ab? ]]
或?
的某些值(例如[ a =~ a ]
或printf 'ab\n' | grep -Eq 'ab?'
)失败,并且如果awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
和[]
看起来像十进制整数,则进行数值比较。 [[ ]]
可以同时解决这两个问题。³,并且对于某些
[[ ]]
或[
值(如[[...]]
或a
)也失败。没有启用(例如b
)5,尽管不需要分组(这里使用
+
命令组而不是index
,它将运行不必要的子shell),因为a
和b
shell运算符(相对于expr "x$a" '<' "x$b"
和a
,b
运算符或!
/ (
,BASH_COMPAT=3.1
运算符)具有相同的优先级。因此,{...;}
等效。评论
如何使用printf'ab'| grep -Eq'ab?'内是否[…]?
–meeDamian
16年5月25日在5:02
@meeDamian if(printf'ab'| grep -Eq'a');然后回显“ a”; fi。 []是与grep类似的命令。我不确定该命令上是否不需要():我添加该字符是因为|,取决于Bash解析事物的方式。如果没有|我敢肯定,即使cmd arg arg,您也可以写;然后。
– Ciro Santilli郝海东冠状病六四事件法轮功
16年5月25日在5:56
@meeDamian是的,似乎不需要():stackoverflow.com/questions/8965509 / ...
– Ciro Santilli郝海东冠状病六四事件法轮功
16年5月25日在6:01
不错的清单!另请参阅:wiki.ubuntu.com/…
–radistao
18-2-27在13:23
#4 楼
单个括号,即[]
符合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
#5 楼
根据对手册页相关部分的快速阅读,主要的区别似乎是==
和!=
运算符与模式而不是文字字符串匹配,而且还有=~
regex比较运算符。
评论
如果您还想知道完全不使用括号,例如在if语句的上下文中,请参阅mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D同样,来自Ubuntu的文档:wiki.ubuntu.com/…
另请参见stackoverflow.com/questions/13542832/…、unix.stackexchange.com/questions/3831/…
请参阅有关堆栈溢出的相关信息:一元运算符应为