最近在一次代码审查中,一位同事声称[[ ]]
结构优于[ ]
构造中的[ ]
php
if [ "`id -nu`" = "$someuser" ] ; then echo "I love you madly, $someuser" fi
他没法提供理由。 有吗? html
[[]]双括号在某些版本的SunOS下未被移植,而且在函数声明中彻底没有报告:GNU bash,版本2.02.0(1)-release(sparc-sun-solaris2.6) git
一个典型的状况,你不能使用[[在autotools configure.ac脚本中,括号有一个特殊和不一样的含义,因此你将不得不使用test
而不是[或[[ - 注意测试和[是相同的]程序。 github
简而言之,[[更好,由于它不会分叉另外一个进程。 没有括号或单个括号比双括号慢,由于它要求另外一个进程。 正则表达式
行为差别 shell
关于Bash 4.3.11的一些区别: ubuntu
POSIX vs Bash扩展: bash
[
是POSIX [[
是一个Bash扩展¹记录在: https : //www.gnu.org/software/bash/manual/bash.html#Conditional-Constructs 常规命令vs魔法 less
[
只是一个带有奇怪名字的常规命令。 ide
]
只是[
阻止进一步使用参数的论点]
。
Ubuntu 16.04实际上在/usr/bin/[
由coreutils提供了它的可执行文件,可是bash内置版本优先。
Bash解析命令的方式没有任何改变。
特别是, <
是重定向, &&
和||
链接多个命令, ( )
生成子shell,除非由\\
转义,而且像往常同样进行单词扩展。
[[ X ]]
是一个使X
被神奇地解析的单一构造。 <
, &&
, ||
和()
是专门处理的,而且分词规则是不一样的。
还有其余差别,如=
和=~
。
在Bashese: [
是一个内置命令, [[
是一个关键字: https ://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]
:词典比较 [ a \\< b ]
:与上述相同。 \\
required或者重定向,就像任何其余命令同样。 Bash扩展。 expr a \\< b > /dev/null
:POSIXequivalent²,请参阅: 如何在Bash中测试字典小于或等于的字典? &&
和||
[[ a = a && b = b ]]
:true,逻辑和 [ a = a && b = b ]
:语法错误, &&
解析为AND命令分隔符cmd1 && cmd2
[ a = a -ab = b ]
:等效,但由POSIX³弃用 [ a = a ] && [ b = b ]
:POSIX和可靠的等价物 (
[[ (a = a || a = b) && a = b ]]
:false [ ( a = a ) ]
:语法错误, ()
被解释为子shell [ \\( a = a -oa = b \\) -aa = b ]
:等效,但POSIX不推荐使用()
{ [ a = a ] || [ a = b ]; } && [ a = b ]
{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX等价物⁵ 扩展时的单词拆分和文件名生成(split + glob)
x='a b'; [[ $x = 'ab' ]]
x='a b'; [[ $x = 'ab' ]]
:true,不须要引号 x='a b'; [ $x = 'ab' ]
x='a b'; [ $x = 'ab' ]
:语法错误,扩展为[ ab = 'ab' ]
x='*'; [ $x = 'ab' ]
x='*'; [ $x = 'ab' ]
:若是当前目录中有多个文件,则会出现语法错误。 x='a b'; [ "$x" = 'ab' ]
x='a b'; [ "$x" = 'ab' ]
:POSIX等价物 =
[[ ab = a? ]]
[[ ab = a? ]]
:是的,由于它确实模式匹配 ( * ? [
是魔术]。 不会将glob扩展为当前目录中的文件。 [ ab = a? ]
[ ab = a? ]
: a?
glob扩展。 所以多是真或假,具体取决于当前目录中的文件。 [ ab = a\\? ]
[ ab = a\\? ]
:false,不是glob扩展 =
和==
是在两个相同的[
和[[
但==
是一个bash扩展。 case ab in (a?) echo match; esac
case ab in (a?) echo match; esac
:POSIX等价物 [[ ab =~ 'ab?' ]]
[[ ab =~ 'ab?' ]]
:false⁴,用''
失去魔力 [[ ab? =~ 'ab?' ]]
[[ ab? =~ 'ab?' ]]
:是的 =~
[[ 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 shell中的等效[[...]]
结构
²可是a
或b
某些值(如+
或index
)失败,而且若是a
和b
看起来像十进制整数则进行数值比较。 expr "x$a" '<' "x$b"
适用于二者。
³而且也失败了a
或b
某些值!
或(
。
⁴在bash 3.2及以上版本中提供与bash 3.1的兼容性未启用(与BASH_COMPAT=3.1
)
⁵虽然分组(此处带有{...;}
命令组而不是(...)
将运行没必要要的子shell)不是必需的||
和&&
shell运算符(而不是||
和&&
[[...]]
运算符或-o
/ -a
[
运算符]具备相同的优先级。 因此[ a = a ] || [ a = b ] && [ a = b ]
[ a = a ] || [ a = b ] && [ a = b ]
将是等价的。
若是您要关注Google的风格指南 :
测试,[和[[
[[...]]减小了错误,由于在[[和]]和[[...]]之间没有发生路径名扩展或分词,容许正则表达式匹配,而[...]则没有。
# This ensures the string on the left is made up of characters in the # alnum character class followed by the string name. # Note that the RHS should not be quoted here. # For the gory details, see # E14 at https://tiswww.case.edu/php/chet/bash/FAQ if [[ "filename" =~ ^[[:alnum:]]+name ]]; then echo "Match" fi # This matches the exact pattern "f*" (Does not match in this case) if [[ "filename" == "f*" ]]; then echo "Match" fi # This gives a "too many arguments" error as f* is expanded to the # contents of the current directory if [ "filename" == f* ]; then echo "Match" fi