我只是想知道两者之间到底有什么区别
[[ $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外壳中的等效构造
²,但对于a
or的某些值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