雙方括號[[]]比Bash中的單方括號[]更好嗎?

最近在一次代碼審查中,一位同事聲稱[[ ]]結構優於[ ]構造中的[ ] php

if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi

他沒法提供理由。 有嗎? html


#1樓

[[]]雙括號在某些版本的SunOS下未被移植,而且在函數聲明中徹底沒有報告:GNU bash,版本2.02.0(1)-release(sparc-sun-solaris2.6) git


#2樓

一個典型的狀況,你不能使用[[在autotools configure.ac腳本中,括號有一個特殊和不一樣的含義,因此你將不得不使用test而不是[或[[ - 注意測試和[是相同的]程序。 github


#3樓

簡而言之,[[更好,由於它不會分叉另外一個進程。 沒有括號或單個括號比雙括號慢,由於它要求另外一個進程。 正則表達式


#4樓

行爲差別 shell

關於Bash 4.3.11的一些區別: ubuntu

  • POSIX vs Bash擴展: bash

  • 常規命令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 = 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等價物。

若是您使用[[ ]]您:

  • 失去便攜性
  • 強迫讀者學習另外一個bash擴展的複雜性。 [只是一個帶有奇怪名稱的常規命令,不涉及特殊語義。

¹靈感來自Korn shell中的等效[[...]]結構

²可是ab某些值(如+index )失敗,而且若是ab看起來像十進制整數則進行數值比較。 expr "x$a" '<' "x$b"適用於二者。

³而且也失敗了ab某些值! (

⁴在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 ]將是等價的。


#5樓

若是您要關注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
相關文章
相關標籤/搜索