web-dev-qa-db-ja.com

Bashの単一角括弧と二重角括弧の違い

私はifに関するbashの例を読んでいますが、いくつかの例は単一の角括弧で書かれています:

if [ -f $param ]
then
  #...
fi

その他の二重角かっこ:

if [[ $? -ne 0 ]]
then
    start looking for errors in yourlog
fi

違いはなんですか?

139
rkmax

単一の[]は、posix Shell準拠の条件テストです。

Double [[]]は、標準[]の拡張であり、bashおよびその他のシェル(zsh、kshなど)でサポートされています。追加の操作(および標準のposix操作)をサポートします。例:||の代わりに-oおよび=~と一致する正規表現。相違点のより完全なリストは、 条件付き構文に関するbash手動セクション にあります。

スクリプトをシェル間で移植できるようにする場合は、[]を使用します。 [[]]でサポートされない条件式が必要で、移植性を必要としない場合は、[]を使用します。

161
cmh

行動の違い

Bash 4.3.11でテスト済み:

  • POSIX対Bash拡張機能:

  • 通常コマンドvsマジック

    • [は、奇妙な名前の通常のコマンドです。

      ][の単なる引数であり、これ以上の引数が使用されないようにします。

      Ubuntu 16.04には、coreutilsが提供する/usr/bin/[に実際に実行可能ファイルがありますが、bashの組み込みバージョンが優先されます。

      Bashがコマンドを解析する方法に変更はありません。

      特に、<はリダイレクト、&&および||は複数のコマンドを連結し、( )\でエスケープされない限りサブシェルを生成し、Wordの展開は通常どおり行われます。

    • [[ X ]]は、Xを魔法のように解析する単一の構成体です。 <&&||、および()は特別に処理され、Wordの分割ルールは異なります。

      ==~などの違いもあります。

      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 ]]:true、論理and
    • [ a = a && b = b ]:構文エラー、&& ANDコマンド区切りとして解析cmd1 && cmd2
    • [ a = a -a b = b ]:同等ですが、POSIX³で非推奨
    • [ a = a ] && [ b = b ]:POSIXおよび同等の信頼できる
  • (

    • [[ (a = a || a = b) && a = b ]]:false
    • [ ( a = a ) ]:構文エラー、()はサブシェルとして解釈されます
    • [ \( 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' ]]:true、引用符は不要
    • x='a b'; [ $x = 'a b' ]:構文エラー、[ a b = 'a b' ]に展開
    • x='*'; [ $x = 'a b' ]:現在のディレクトリに複数のファイルがある場合の構文エラー。
    • x='a b'; [ "$x" = 'a b' ]:POSIXと同等
  • =

    • [[ ab = a? ]]:true パターンマッチング* ? [は魔法)を行うため。現在のディレクトリ内のファイルに展開しません。
    • [ ab = a? ]a? globが展開されます。したがって、現在のディレクトリ内のファイルに応じて、trueまたはfalseになる場合があります。
    • [ ab = a\? ]:glob展開ではなくfalse
    • ===[[[の両方で同じですが、==はBash拡張機能です。
    • case ab in (a?) echo match; esac:POSIXと同等
    • [[ ab =~ 'ab?' ]]:false4''で魔法を失います
    • [[ ab? =~ 'ab?' ]]:true
  • =~

    • [[ 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シェルの同等の[[...]]コンストラクトに触発された

²ただし、aまたはbの一部の値(+またはindexなど)で失敗し、abが似ている場合は数値比較を行います。 10進整数。 expr "x$a" '<' "x$b"は両方を回避します。

³また、!(のようなaまたはbの一部の値でも失敗します。

4 bash 3.2以降では、bash 3.1との互換性が提供されていません(BASH_COMPAT=3.1など)

5 ただし、グループ化(ここでは、不要なサブシェルを実行する{...;}の代わりに(...)コマンドグループ)は、||および&&シェル演算子としては必要ありません( ||および&&[[...]]演算子または-o/-a[演算子)の優先順位は同じです。したがって、[ a = a ] || [ a = b ] && [ a = b ]は同等です。

条件テスト用の単一の角かっこ(つまり[...])内では、単一の=などの一部の演算子はすべてのシェルでサポートされていますが、演算子==の使用は一部の古いシェルではサポートされていません。

条件テストの二重括弧([[...]])内では、古いシェルと新しいシェルで=または==を使用しても違いはありません。

編集:私も注意する必要があります:bashでは、可能であれば常に二重角括弧[[...]]を使用してください。単一角括弧よりも安全です。次の例でその理由を説明します。

if [ $var == "hello" ]; then

$ varがnull /空の場合、スクリプトは次のように表示されます。

if [ == "hello" ]; then

スクリプトが壊れます。解決策は、二重角括弧を使用するか、変数を常に引用符で囲むことです("$var")。二重括弧は、より防御的なコーディングの実践です。

14
sampson-chen

[[は、[コマンドに似た(ただしより強力な)bashキーワードです。

見る

http://mywiki.wooledge.org/BashFAQ/031 および http://mywiki.wooledge.org/BashGuide/TestsAndConditionals

POSIX sh用に書いているのでない限り、[[をお勧めします。

10
Gilles Quenot

Bashマニュアル 言う:

[[と共に使用すると、「<」および「>」演算子は現在のロケールを使用して辞書式にソートされます。テストコマンドは、ASCII順序を使用します。

(テストコマンドは[]と同じです)

1
user5500105

軽い正規表現のマッチングに二重角括弧を使用できます。 :

if [[ $1 =~ "foo.*bar" ]] ; then

(使用しているbashのバージョンがこの構文をサポートしている限り)

1
asf107