Bash 演算子[[ vs [ vs ( vs((?

Bash 演算子[[ vs [ vs ( vs((?

bash(括弧、二重括弧、角括弧、および二重括弧)で使用すると、これらの演算子がどのように異なるかが少し混乱します。

[[ , [ , ( , ((

私は人々が次の文でその表現を使用しているのを見ましたif

if [[ condition ]]

if [ condition ]

if ((condition))

if (condition)

答え1

Bourneのようなシェルでは、ifステートメントは通常次のようになります。

if
   command-list1
then
   command-list2
else
   command-list3
fi

thencommand-list1この句は、コマンドリストの終了コードが0の場合に実行されます。終了コードが0でない場合、elseこの句が実行されます。 command-list1それは簡単でも複雑でもかまいません。たとえば、;newlines演算子の1つで区切られた1つ以上のパイプシーケンスです。以下に示す条件は特別な場合に過ぎません。&&&||ifcommand-list1

  1. if [ condition ]

    [test伝統的なコマンドの別の名前です。[/はtest標準POSIXユーティリティです。すべてのPOSIXシェルにはこの機能が組み込まれています(POSIX²では必要ありませんが)。コマンドはtest終了コードを設定し、ifステートメントはそれに応じてアクションを実行します。一般的なテストは、ファイルが存在するか、1つの数字が別の数字と同じかどうかです。

  2. if [[ condition ]]

    testこれは1の新しいアップグレードバリアントです。ケシそれ強く打つ扱いにくいヤッシュ忙しい箱またサポートされます。この[[ ... ]]構成は終了コードも設定し、if文はそれに応じて動作します。拡張機能の中で、文字列がワイルドカードパターンと一致するかどうかをテストできます。忙しい箱)。

  3. if ((condition))

    その他ケシ拡張理論強く打つそして扱いにくいまたサポートされます。これにより算術演算が実行されます。算術の結果、終了コードが設定され、ifそれに応じて文が実行されます。算術計算結果が0でない場合は、終了コード0(true)を返します。同様に、[[...]]この形式はPOSIXではないため、移植性はありません。

  4. if (command)

    これはサブシェルでコマンドを実行します。コマンドが完了すると、終了コードが設定され、ifそれに応じてステートメントが実行されます。

    これらのサブシェルを使用する一般的な理由は、command必要なcommand変数の割り当てやシェル環境への他の変更による副作用を制限するためです。これらの変更は、サブシェルが完了しても維持されません。

  5. if command

    コマンドが実行され、ifステートメントは終了コードに従って動作します。

[ ... ]and には[[ ... ]]周囲にスペースが必要ですが、(...)and((...))には必要ありません。


1 実際のコマンドではありませんが、特殊なシェル構造ですが、構文は通常のコマンドとは異なり、異なるシェル実装の間に大きな違いがあります。

²POSIXにはシステムにスタンドアロンユーティリティが必要ですtestが、[POSIXの場合、[複数のLinuxディストリビューションにはこのユーティリティが不足していることが知られています。

答え2

  • (…)括弧は次のことを示します。サブシェル。内部コンテンツは他の多くの言語の表現とは異なります。これはコマンドのリストです(角かっこの外側と同様)。これらのコマンドは別々の子プロセスで実行されるため、角かっこ内で行われたリダイレクト、割り当てなどは角かっこの外側には影響しません。
    • 前にドル記号がある$(…)のはコマンドの置き換え:角括弧は、出力がコマンドラインの一部として使用されるコマンドを囲みます(追加の拡張後、二重引用符の間に置換がある場合を除く)。他の物語)。
  • { … }中かっこはコマンドをグループ化する点でかっこに似ていますが、解析にのみ影響し、グループ化には影響しません。プログラムは2のx=2; { x=4; }; echo $x代わりに4を印刷しますx=2; (x=4); echo $x。 (中括弧も同様です。キーワード{;コマンド位置(したがって前後のスペース)では区切りと照会が必要です}が、括弧はそうではありません。それは構文上の問題です。 )
    • 前にドル記号がある${VAR}のはパラメータ拡張、変数値に展開され、追加の変換を実行できます。シェルはksh93${ cmd;}サブシェルを生成しないコマンドの代替形式もサポートします。
  • ((…))二重括弧はaを囲みます。算術命令つまり整数の計算であり、その構文は他のプログラミング言語と似ています。この構文は、主に割り当ておよび条件文に使用されます。これはksh / bash / zshにのみ存在し、通常のshには存在しません。
    • 算術式にも同じ構文が使用され、$((…))式の整数値に拡張されます。
  • [ … ]シングルカッコ条件式。条件式は主に以下に基づいています。オペレーター例には、-n "$variable"変数が空であることをテストし、-e "$file"ファイルが存在するかどうかをテストすることが含まれます。各演算子の周囲には空白が必要です(例:not)、[ "$x" = "$y" ]角括弧の内側には[ "$x"="$y" ]スペースや文字が必要です(例:not)。;[ -n "$foo" ][-n "$foo"]
  • [[ … ]]二重括弧は、いくつかの追加機能を含む条件式の別の形式です。たとえば、[[ -L $file && -f $file ]]ファイルが通常のファイルへのシンボリックリンクであることを確認するテストを書くことができますが、単一の括弧には[ -L "$file" ] && [ -f "$file" ]空白があり引用符を持たないパラメータ拡張が二重括弧[[内では機能しますが、単一括弧[では機能しません]はなぜですか?このトピックに関する追加情報。

シェルでは、すべてcommand は条件付きコマンドです。すべてのコマンドには、成功した場合は0、失敗した場合は1から255までの整数(一部のシェルではより多くの可能性があります)の戻り状態があります。コマンド[ … ](または構文形式)は、スペルを入力することも、ファイルが存在する場合、文字列が空でない場合、または数値が他のものより小さい場合に成功する特定の[[ … ]]コマンドです。数字が他の数字より小さい場合、文法的形式は成功します。 0ではありません。以下は、シェルスクリプトの条件文の例です。test …((…))

  • myfile文字列が含まれているかどうかをテストしますhello

    if grep -q hello myfile; then …
    
  • mydirディレクトリの場合は、そのディレクトリに変更して次の操作を行います。

    if cd mydir; then
      echo "Creating mydir/myfile"
      echo 'some content' >myfile
    else
      echo >&2 "Fatal error. This script requires mydir to exist."
    fi
    
  • myfile現在ディレクトリに呼び出されているファイルがあるかどうかをテストします。

    if [ -e myfile ]; then …
    
  • 同じですが、ぶら下がっているシンボリックリンクも含まれます。

    if [ -e myfile ] || [ -L myfile ]; then …
    
  • x値(数字と仮定)が2以上であることをテストします。

    if [ "$x" -ge 2 ]; then …
    
  • bash / ksh / zshの値(数字と仮定)xが2以上であることをテストします。

    if ((x >= 2)); then …
    

答え3

[そして[[

[この回答は質問の対サブ​​セットをカバーしています。[[

Bash 4.3.11のいくつかの違い:

  • POSIXとBash拡張:

  • 一般コマンドと魔法

    • [奇妙な名前を持つ一般的なコマンドです。

      ]最後のパラメータです[

      Ubuntu 16.04には、実際には次/usr/bin/[のような実行可能ファイルがあります。コアツールしかし、bashの組み込みバージョンが優先されます。

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

      具体的には、<リダイレクトと複数のコマンド接続はエスケープされない限りサブシェルを生成し、&&ワード拡張は通常どおり発生します。||( )\

    • [[ X ]]X魔法のように解析できる単一の構文です。<、、、、&&および||その他の()特殊処理では、単語分割規則が異なります。

      =とのような追加の違いがあります=~

    Basheseでは:は[組み込みコマンドと[[キーワードです。https://askubuntu.com/questions/445749/whats-the-difference-Between-shell-builtin-and-shell-keyword

  • <

  • &&そして||

    • [[ a = a && b = b ]]:真で論理的そして
    • [ a = a && b = b ]: 構文エラー、&&AND コマンド区切り文字で解析cmd1 && cmd2
    • [ a = a ] && [ b = b ]: POSIXの安定した同等物
    • [ a = a -a b = b ]:ほとんど同じですが、特定の値aや論理演算として解釈された場合、または異常にb失敗したため、POSIXでは廃止されました。!(
  • (

    • [[ (a = a || a = b) && a = b ]]:間違っています。そうでない場合よりも優先順位が高い( )ので true になります。[[ && ]][[ || ]]
    • [ ( a = a ) ]:構文エラー、()サブシェルとして解釈されました
    • [ \( a = a -o a = b \) -a a = b ]:同じですが、POSIXは、および()を使用しなくなりました-a-oない場合は真です。優先順位が次より高い\( \)からです。-a-o
    • { [ a = a ] || [ a = b ]; } && [ a = b ]廃止予定のPOSIXと同じです。ただし、この特別な場合には、次のように書くことができます。[ a = a ] || [ a = b ] && [ a = b ]なぜなら||、シェル演算子はandと、とは異なり、&&同じ優先順位を持つからです。[[ || ]][[ && ]]-o-a[
  • 拡張中の単語分割とファイル名の生成(split+glob)

    • x='a b'; [[ $x = 'a b' ]]:そうです。引用は必要ありません。
    • x='a b'; [ $x = 'a b' ]:構文エラーです。次に展開されます。[ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]:現在のディレクトリに複数のファイルがある場合、構文エラーが発生します。
    • x='a b'; [ "$x" = 'a b' ]: POSIXに対応
  • =

    • [[ ab = a? ]]:本当だ、それは本当だからなパターンマッチング* ? [魔法です)。グローバルを現在のディレクトリのファイルに拡張しないでください。
    • [ ab = a? ]a?グローバル拡張。したがって、現在のディレクトリのファイルに応じてtrueまたはfalseにすることができます。
    • [ ab = a\? ]:false、グローバル拡張ではありません。
    • =and と と同じです==が、 Bash 拡張があります。[[[==
    • case ab in (a?) echo match; esac: POSIXに対応
    • [[ ab =~ 'ab?' ]]:false、''Bash 3.2以降では魔法が消え、bash 3.1との互換性は有効になりません(と同じBASH_COMPAT=3.1)。
    • [[ ab? =~ 'ab?' ]]:本物
  • =~

    • [[ ab =~ ab? ]]: 正確さ、POSIX拡張正規表現マッチング、?グローバルに展開されていない
    • [ a =~ a ]:文法エラー。 bashに該当するものはありません。
    • printf 'ab\n' | grep -Eq 'ab?':POSIXに対応(単一データ行のみ)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?':POSIXと同じです。

推奨事項:常に使用[]

[[ ]]私が見たすべての設定にはPOSIXと同等の設定があります。

あなたがあなたを使用している場合[[ ]]

  • 移植性の喪失
  • 読者に別のbash拡張の複雑さを学ぶように強制します。[特別な意味を持たない奇妙な名前を持つ一般的なコマンドです。

ありがとうスティーブン・チャジェラス重要な修正と追加が行われました。

答え4

いくつかの例:

既存のテスト:

foo="some thing"
# check if value of foo is not empty
if [ -n "$foo" ] ; then... 
if test -n "$foo" ; then... 

testコマンドは[他のコマンドと同じであるため、変数を引用符で囲まないと単語に分割されます。

現代的なテスト

[[ ... ]]わずかに異なる動作をする(最新の)特別なシェル構成で、特に変数をトークン化しないという点で注目に値します。

if [[ -n $foo ]] ; then... 

一部ドキュメントはここ[[[ここにあります

算術テスト:

foo=12 bar=3
if (( $foo + $bar == 15 )) ; then ...  

「一般」コマンド:

上記のすべてのコマンドは通常のコマンドのように動作し、すべてのifコマンドを受け入れることができます。

# grep returns true if it finds something
if grep pattern file ; then ...

複数のコマンド:

あるいは、複数のコマンドを使用することもできます。コマンドセットを( ... )サブシェルにラップして実行し、一時的なシェルの状態(作業ディレクトリ、変数)のコピー。一時的に別のディレクトリでプログラムを実行する必要がある場合:

# this will move to $somedir only for the duration of the subshell 
if ( cd $somedir ; some_test ) ; then ...

# while here, the rest of the script will see the new working
# directory, even after the test
if cd $somedir ; some_test ; then ...

関連情報