最近在一次代碼審查中,一位同事聲稱[[ ]]
結構優於[ ]
構造中的[ ]
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