Bashにおける[[ ]] AND [ ]と(( )) AND ( )の違い

Bashにおける[[ ]] AND [ ]と(( )) AND ( )の違い

[[ condition ]]および[ condition ](( condition ))の使用の違いは何ですか( condition )? どのようなシナリオでこれらのいずれかを使用する必要がありますか?

  • (( 10 > 9 ))動作するが(( 10 -gt 9 ))動作しない
  • [[ 10 -gt 9 ]]動作するが[[ 10 > 9 ]]動作しない

答え1

((...))シェルの算術構文。使用できる演算子はマニュアルに記載されています。6.5 シェル演算

(...)グループ化サブシェル内に含まれるコマンドを実行する構文:3.2.4.3 コマンドのグループ化

[...]は「レガシー」条件構文です。ドキュメントは6.4 Bash 条件式

[[...]]は、実行できることすべてを実行します[...]。違いは、内部の変数に対して単語分割とグロブ展開が実行されない[[...]]ため、変数を引用符で囲むことはそれほど重要ではないことです。さらに、次のように[[実行できます。パターンマッチングオペレータ==正規表現マッチングオペレーターと=~

[[ 10 > 9 ]]予期しない結果になる理由は、>内部の演算子[[...]]文字列比較文字列「10」は文字列「9」より「小さい」です。

答え2

について((…))(…)

前述の通りこの他の答えは、((…))シェルの算術構文(バシズム) を実行し、(…)サブシェルでコマンドを実行します。これらは互いに大きく異なり、[ … ]やとも異なります[[ … ]]

一方[ … ]、 と は[[ … ]]単純なケースでは非常に似ているため、混同されることがあります。この回答の残りの部分では、[ … ]とに焦点を当てます[[ … ]]


正式なメモ

ここでの私の目標は次のとおりです。

  • 詳しく説明する[ … ]との違いと類似点[[ … ]];
  • [ … ]vsの主題で標準的な回答を提供するため、「 is not 」[[ … ]]で回答できる質問はここにリンクできます。[[[
  • 十分に網羅的な回答を提供することで、ユーザーはそれぞれ 1 つの違いに焦点を当てた回答を投稿する誘惑に駆られなくなります。

とは[

  1. [テストを実行します。

    の目的は[、何かをテストし (たとえば、ファイルが存在するかどうか)、テストが成功した場合は終了ステータス 0 を返し、それ以外の場合は 0 以外の値を返すことです。

  2. [コマンドです。

    [catは、または のようなコマンド名ですecho[( のようにecho) は Bash に組み込まれていますが、これは追加のプロセスを生成せずに実行できることを意味しているだけで、コマンドのように動作します。[システムにはスタンドアロンの実行可能ファイル (例/bin/[)がある可能性がありますtype -a [。Bash で試して確認してください。

  3. [後にスペースが必要です。

    コマンドとして、[は引数を取ります。他のコマンドと同様に、引数は互いに、またコマンド名から分離する必要があります。 は[foo異なるコマンド名であるため、 と同等ではありません[ foo(同様に、 も明らかに と同等でechoHello worldはありませんecho Hello world)。 の後には必ずスペース (またはタブ) が必要です[

  4. [必要]

    [は最後の引数として を必要とします]。そうでない場合、 は動作しません。 これは、 が[ … ]特別な構文であるかのようにブロックとして目立つようにするためだけのものですが、特別な構文ではありません。 を]最後の引数として渡すには、その前にスペース (またはタブ) が必要です。 比較すると、 の最後の引数は[ … bar]ですが、bar]ではないため、 は有効なコマンドではありません。][ … bar]

  5. [は(ほぼ) のようなものですtest

    [ … ]は と同等ですtest …。つまり、を削除してコマンド名を変更することで、任意の[コマンドをコマンドに変換できます。また、コマンド名を変更して を追加することで、任意のコマンドを コマンドに変換できます。test]test[]

  6. [特別なことではありません。

    覚えておくと良いのは[、これは特別なものではなく、コマンドのちょっと派手な名前にすぎないということです。これを認めれば、次の事実に驚かないでしょう。全てシェルが行う解析と処理前にコマンド (testまたはechoなどls) の実行は、コマンドが の場合にも発生します[。具体的には、次のようになります。

    • [引数が引用符で囲まれているかどうかは認識されないため、シェルが引用符を削除した後に引数を取得します。

    • 引用符で囲まれておらず&&、エスケープもされていない、または||と の間にある は、の引数として解釈されません。言い換えると、は( がないため無効)、(別のコマンド、それが何であれ) と論理的に接続されていると解釈され、 とまったく同じになります。[][[ … || … ][ …]… ]||command1 || command2

  7. [POSIX で規定されています。

    そこには[/の POSIX 仕様testポータブルで通話できます[。注:

    • いくつかのプライマリは拡張機能であり、いくつかは廃止予定としてマークされています。たとえば、無効なコード ( [ … || … ]) は として修正できます[ … -o … ]が、 は-o廃止予定であるため、 の方が適切な修正方法です[ … ] || [ … ]
    • 実装によっては、さらに多くのプライマリがサポートされる場合があります。Bash[の組み込みではサポートされます (を参照help test)。OSの[バイナリ (など/bin/[) ではサポートされる可能性があります (を参照man test)。

とは何ですか?と[[どう違うのですか?[[[

注:
- この質問にはタグが付けられています、今私たちが話しているのは[[ バッシュで.
- このセクションの番号付き段落は、前のセクションの番号付き段落に対応しています。

  1. (類似性)[[テストを実行します。

    の目的[[は、何かをテストし (たとえば、ファイルが存在するかどうか)、テストが成功した場合は終了ステータス 0 を返し、そうでない場合は 0 以外の値を返すことです。何でもテストでき、さらにそれ以上の[[こともテストできます。[

  2. (違い)[[キーワードです。

    [[​はシェルキーワードですtype [[これを確認するにはBashで呼び出してください)。[組み込みと同様に、[[キーワードはBashに属しますが、ではないコマンドのように動作します。

  3. (類似性)[[後にスペースが必要です。

    (またはタブ)

  4. (類似性)[[必要]]

    [[]]はコードの後半で必要になりますが、[[ … ]]ブロックとして目立たせるためだけではありません。これは特別な構文です (違いについては後で説明します)。 の前にはスペース (またはタブ) が必要です]]

  5. (違い)と同等の通常のコマンドはありません[[

    置き換えできる[[方法で置き換えできる他のコマンド/キーワード/その他はありません。test[

  6. (違い)[[ 特別。

    [[は、一致する までのコードを解析および解釈する方法を変更します。または(またはなど)]]を実行する前にシェルが行う通常の解析と処理は、の内部には適用されません。特に、[testechols[[ … ]]

    • [[ 引数を引用符で囲んだかどうかに注意してください。変数を二重引用符で囲む必要はありません(通常はそれは)ですが、場合によっては文字列(または変数)を二重引用符で囲むと違いが生じます(この答え=ここでは、「または==または!=またはの右側=~」と記載されています。

    • &&またはと||の間は構造に属します。は と実質的に同等の有効なコードである可能性があります。[[]][[ … ]][[ … || … ]][[ … ]] || [[ … ]]

  7. (違い)[[POSIX では指定されていません。

    [[​は移植性があり[[では動作しますが、純粋な では動作しませんsh。他のシェルはサポートしている可能性があります[[(例: Zsh はサポートしています) が、 Bash の[[とは異なる場合があります[[

    [[[は/の仕様に準拠するようには設計されていませんtest。多くの場合、[を に[[]を に置き換えると、元のスニペットと同等のスニペット]]が得られますが、常にそうとは限りません。[[ … ]][ … ]時々内部を調整する必要があります。したがって、盲目的[に変更しないでください[[。盲目的[[に変更することは、実行できる[テストと実行できないテストがあるため、さらに危険です。[[[


その他の注意事項:

  1. も も構文の一部ではあり[ません。 は、コードの終了ステータスをテストするだけであることを覚えておいてください。は有効です。は有効です。 同様にまたは も有効です (または部分自体が有効なスニペットである場合)。[[if … then …ifif true; then …if sleep 5; then …if [ … ]; then …if [[ … ]]; then …[ … ][[ … ]]

    ((…))またはも何らかの終了ステータスを返すため(…)(内容によって異なります)、 の後にifも使用できます。

  2. 個人的には、簡単に実行できる[テストには を使用し、本当に必要なときにのみ使用することを好みます。こうすることで、非移植性に慣れることがなくなり、Bash ほど機能が豊富ではないシェルで何ができるかがわかります。[[[[[

  3. [OS の実行可能ファイルは、必ずしも Bash の組み込みファイルと厳密に同等であるとは限りません。[[Bash によって呼び出された場合は、組み込みファイルが機能します。 が[他の何かによって呼び出された場合は、実行可能ファイルが機能します。たとえば、 はfind … -exec [ … ] …実行可能ファイルを使用します。標準の実行可能ファイルは存在しないため[[(少なくとも私が知っているシステムでは)、 はfind … -exec [[ … ]] …機能しません。 実行可能ファイルが存在する場合[[、コマンドのように動作する必要があり、キーワードを模倣することはできません。

答え3

[ ] と [[ ]] の間には大きな違いがあります。

a=0;
if [ $a = 1 -a $(grep ERR 1.log|wc -l) -ne 0 ];then
      echo "error";
fi 

[ ] を使用する場合、and 演算子 -a は短絡評価をサポートしません。上記のコードでは、最初の条件が false を返しても、2 番目の条件は評価されます。ファイル 1.log が存在しない場合は、「そのようなファイルまたはディレクトリはありません」というエラーが表示されます。

しかし[[ ]]の場合:

a=0
if [[ $a = 1 && $(grep ERR 1.log|wc -l) -ne 0 ];then
    echo "error"
fi

ファイル「1.log」が存在しない場合でも、最初の条件が偽であるため、2 番目の条件は評価されないため、問題ありません。

答え4

これをコメントに書きたかったのですが、まだ許可されていません。

[] と [[]] の違いとして私が気づいたのは、前者では複数の比較を使用できることです。

同じ比較は[[]]で構文エラーをスローします

a=1
b=2

これは機能します:

$  [ "$a" -gt 0 -a "$b" -gt "$a" ] && { echo '[b>a>0]'; }
[b>a>0]

これは動作しません:

$ [[ $a -gt 0 -a $b -gt $a ]] && { echo '[[b>a>0]]'; }
-bash: syntax error in conditional expression
-bash: syntax error near `-a'

なぜそうなるのかを詳しく調べたわけではありませんが、多重比較を使用する場合は [] を使用します。

関連情報