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


161

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

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

角かっこが二重になっているもの:

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

違いはなんですか?


3
あなたはこの質問の答えを見て、あなたの答えを得ることができます: unix.stackexchange.com/questions/3831/...
アミールNaghizadeh

参照してくださいserverfault.com/questions/52034/...
pevik

回答:


188

シングル[]はposixシェル準拠の条件テストです。

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

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


6
スクリプトが、サポートするシェルを明示的に要求するシバンで始まっていない場合[[ ]](例:bash with #!/bin/bashまたは#!/usr/bin/env bash)、ポータブルオプションを使用する必要があることを付け加えます。/ bin / shがこのような拡張機能をサポートすることを前提とするスクリプトは、最近のDebianやUbuntuのリリースのようなOSでは機能しません。
ゴードンデイ

87

行動の違い

Bash 4.3.11でテスト済み:

  • POSIX vs Bash拡張:

  • 通常のコマンド対魔法

    • [ 変な名前の通常のコマンドです。

      ][それ以上の引数が使用されないようにするための単なる引数です。

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

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

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

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

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

      バシェス語で[は:は組み込みコマンドであり[[、キーワードです: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 -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?グロブが拡張されます。したがって、現在のディレクトリ内のファイルに応じて、trueまたはfalseになります。
    • [ ab = a\? ]:false、グロブ拡張ではない
    • =そして==、両方で同じである[[[、しかし==バッシュの拡張機能です。
    • case ab in (a?) echo match; esac:POSIX相当
    • [[ ab =~ 'ab?' ]]:false 4、魔法を失う''
    • [[ 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拡張機能の複雑さを学習させる。[奇妙な名前の通常のコマンドであり、特別なセマンティクスは関係しません。

Ko [[...]]Kornシェルの同等の構造に触発

²しかし、いくつかの値のために失敗したab(よう+index)と数値の比較であれば行いab小数、整数のような表情を。expr "x$a" '<' "x$b"両方を回避します。

³ものいくつかの値のために失敗したabのような!、または(

bash 3.2以降では4で、bash 3.1との互換性はありません(などBASH_COMPAT=3.1)。

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


3
私が見たすべての[[]]コンストラクトには、同等のPOSIXがあります。」同じことが、地球の表面にあるチューリング完全言語についても言えます。
A.リック

3
@ A.Rickは、「言語YでXを実行する方法」のすべての質問に対する有効な回答となるでしょう:-)もちろん、そのステートメントには「便利な」暗黙の表現があります。
Ciro Santilli郝海东冠状病六四事件法轮功

6
素晴らしい要約。努力をありがとう。しかし、私はその勧告に同意しません。移植性とより一貫性があり強力な構文です。環境でbash> 4を要求できる場合は、[[]]構文をお勧めします。
Bernard

@Downvotersは私が情報を学び、改善できるように説明してください:-)
Ciro Santilli郝海东冠状病六四事件法轮功

8
すばらしい答えですが、推奨事項:常に使用[]することを私の好みとして読む必要があります[]移植性を失わないようにする場合に使用します。述べたように、ここでPOSIXまたはBourneShellへの移植性/適合性が懸念される場合は、古い構文を使用する必要があります。一方、スクリプトでBASH、Zsh、またはKornShellが必要な場合、新しい構文は通常より柔軟ですが、必ずしも下位互換性があるとは限りません。私はむしろ一緒に行きたい[[ ab =~ ab? ]]私ができる場合と比べて、下位互換性の心配がありませんprintf 'ab' | grep -Eq 'ab?'
MauricioRobayo

14

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

条件テスト(つまり、[[...]])のための二重括弧内には、使用して差がない=か、==古いか新しいシェルでは。

編集:次の点にも注意してください:bashでは、可能な場合は常にダブルブラケット[[...]]を使用してください。シングルブラケットよりも安全だからです。その理由を次の例で説明します。

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

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

if [ == "hello" ]; then

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


1
条件のないすべての変数の読み取りに適用されるので、十分な理由がない限り、変数のすべての読み取りを引用符で囲むことは、はるかに優れた防御的コーディングプラクティスです。ハードドライブ名にスペース(またはそのようなもの)が含まれている場合、iTunesインストーラーのバグにより、人のファイルが削除されていました。それはまたあなたが言及する問題を解決します。
Chai T. Rex


1

二重の大括弧を使用して、簡単な正規表現マッチングを行うことができます。例:

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

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


6
パターンを引用した場合を除き、パターンはリテラル文字列として扱われます。
ormaaj

とても本当です。時々これは私を困らせます:)
asf107

1

バッシュのマニュアルは言う:

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.