一位同事最近在一次代码审查中声称[[ ]]
,[ ]
在诸如以下的构造中,该构造优于
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
他无法提供理由。有一个吗?
一位同事最近在一次代码审查中声称[[ ]]
,[ ]
在诸如以下的构造中,该构造优于
if [ "`id -nu`" = "$someuser" ] ; then
echo "I love you madly, $someuser"
fi
他无法提供理由。有一个吗?
Answers:
[[
具有更少的惊喜,并且通常更安全。但是它不是可移植的-POSIX没有指定它的功能,只有一些shell支持它(除了bash,我听说ksh也支持它)。例如,您可以
[[ -e $b ]]
测试文件是否存在。但是[
,您必须用引号引起来$b
,因为它会拆分参数并扩展类似的内容"a*"
(按[[
字面意义进行处理)。这也与如何[
成为外部程序并像其他程序一样正常地接收其自变量有关(尽管它也可以是内置函数,但是仍然没有这种特殊处理)。
[[
还具有其他一些不错的功能,例如正则表达式匹配=~
以及类似C语言中已知的运算符。这是一个很好的页面:test [
和之间有什么区别[[
?和重击测试
[[ ]]
但解释为与含义相同[ ]
。
#!/bin/sh
但是#!/bin/bash
一旦我依靠某些BASH特定功能,便立即切换使用,以表示该脚本不再是Bourne shell可移植的。
行为差异
Bash 4.3.11的一些区别:
POSIX vs Bash扩展:
常规命令与魔术
[
只是一个带有奇怪名称的常规命令。
]
只是其中的一个论点而[
无法使用进一步的论点。
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等效²,请参阅:如何在Bash中测试小于或等于的字典式字符串?&&
和 ||
[[ 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等效⁵扩展时分词和生成文件名(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?' ]]
:假⁴,失去魔法 ''
[[ 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
喜欢!
或(
。
b在bash 3.2及更高版本中并没有提供与bash 3.1的兼容性(与一样BASH_COMPAT=3.1
)
⁵尽管由于和壳操作符(与和运算符或/ 运算符相对)具有相同的优先级,所以不需要分组(此处使用{...;}
命令组,而不是(...)
将运行不必要的子shell)。因此将是等效的。||
&&
||
&&
[[...]]
-o
-a
[
[ a = a ] || [ a = b ] && [ a = b ]
[
出于相同的原因使用。
[[ ]]
具有更多功能-建议您阅读Advanced Bash脚本指南以获取更多信息,尤其是第7章“测试”中的扩展测试命令部分。
顺便说一句,如指南所述,它[[ ]]
是在ksh88(1988年版本的Korn shell)中引入的。
从哪个比较器,测试,方括号或双方括号最快?(http://bashcurescancer.com)
双括号是一个“复合命令”,其中,test和单括号是shell内置命令(实际上是同一命令)。因此,单括号和双括号执行不同的代码。
测试和单括号是最易携带的,因为它们作为单独的命令和外部命令存在。但是,如果您使用的是BASH的任何远程现代版本,则支持双括号。
[[
可能带来的改进。但是,那我是个老派老屁:-)
[
和test
即使外部的版本也存在。
PS1=...crazy stuff...
和/或$PROMPT_COMMAND
);对于这些,我不希望脚本执行过程中有任何明显的延迟。
apt-get update
如果自上次运行以来已超过X个小时,我需要运行。当人们可以将可移植性从已经太长的代码约束列表中剔除时,这是一个很大的解脱。
如果您要遵循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
[[ -d ~ ]]
返回true(这意味着~
已扩展为/home/user
)。我认为Google的文字应该更加精确。
[[]]双括号在某些版本的SunOS下不支持,而在以下函数声明中则完全不支持:GNU bash,版本2.02.0(1)-release(sparc-sun-solaris2.6)
概括地说,[[更好,因为它不会派生其他进程。没有方括号或单方括号比双方括号要慢,因为它分叉了另一个进程。
type [
以查看此内容。
[[
与截然不同的[
是bash命令行解释器解释的语法。在bash中,尝试输入type [[
。unix4linux是正确的,尽管经典的Bourne-shell [
测试会派生一个新进程来确定真值,但[[
语法(由bash,zsh等从ksh借用)却没有。
[
它内置于Bash和Dash(/bin/sh
在所有Debian衍生的Linux发行版中)。
[[
就其而言,代码是简洁明了的,但是请记住那天,您会使用默认的shell(不是bash
或)将脚本作品移植到系统上ksh
。等[
比较丑陋,繁琐,但AK-47
在任何情况下都可以使用。