Bash演算子の違いは何ですか[[vs [vs(vs((?

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

[[ , [ , ( , (( 

次のようなifステートメントで使用されるのを見たことがあります:

if [[condition]] if [condition] if ((condition)) if (condition) 

コメント

回答

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

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

then句は、コマンドのリストがゼロです。終了コードがゼロ以外の場合、else句が実行されます。 command-list1は単純な場合も複雑な場合もあります。たとえば、演算子;&&&||または改行。以下に示すif条件は、command-list1の特殊なケースです。

  1. if [ condition ]

    [は、従来のtestコマンドの別名です。 [ / testは標準のPOSIXユーティリティです。すべてのPOSIXシェルには組み込みがあります(ただし、POSIX²では必要ありません)。testコマンドは、終了コードとifステートメントを設定します。通常のテストは、ファイルが存在するかどうか、または1つの数値が別の数値と等しいかどうかです。

  2. if [[ condition ]]

    これは、 ksh からtest¹の新しいアップグレードされたバリエーションであり、 bash zsh yash busybox sh もサポートしています。この[[ ... ]]構造は、終了コードとifステートメントはそれに応じて動作します。その拡張機能の中で、文字列がワイルドカードパターンに一致するかどうかをテストできます( busybox sh ではありません)。

  3. if ((condition))

    bash および zsh もサポートする別の ksh 拡張機能。これにより、演算が実行されます。演算の結果として、終了コードが設定され、ifステートメントがaccoとして機能します。ひどく。算術計算の結果がゼロ以外の場合は、ゼロ(true)の終了コードを返します。 [[...]]と同様に、このフォームはPOSIXではないため、移植性がありません。

  4. if (command)

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

    このようなサブシェルを使用する一般的な理由は、の副作用を制限することです。 command commandでシェルの環境に変数の割り当てやその他の変更が必要な場合。このような変更は、サブシェルの完了後も残りません。

  5. if command

    コマンドが実行され、ifステートメントが機能します終了コードによると。


¹ただし、実際にはコマンドではなく、通常のコマンドとは別の構文を持つ特別なシェル構造です。シェルの実装間で大幅に異なる

²POSIXでは、スタンドアロンのtest[ユーティリティは、[の場合、いくつかのLinuxディストリビューションがmであることがわかっています。

コメント

  • 5番目のオプションを含めていただきありがとうございます。これが実際にどのように機能し、驚くほど十分に活用されていないかを理解するための’の鍵です。
  • [は実際には内部コマンドやシンボルではなく、バイナリ。通常、/binに住んでいます。
  • @JulienR。実際には、testと同様に、[が組み込まれています。互換性の理由から利用可能なバイナリバージョンがあります。 help [help testを確認してください。
  • その間((isnt POSIX、$((つまり、算術展開は簡単で、’混乱しやすいです。多くの場合、回避策は[ $((2+2)) -eq 4 ]のようなものを使用することです。条件文で算術を利用する
  • この回答に複数回賛成できたらいいのにと思います。完璧な説明です。

回答

  • (…)括弧はサブシェル。それらの中にあるものは、他の多くの言語のような表現ではありません。コマンドのリスト(括弧の外側と同様)。これらのコマンドは別のサブプロセスで実行されるため、括弧内で実行されるリダイレクト、割り当てなどは、括弧の外側では効果がありません。
    • 先頭にドル記号、$(…)コマンド置換です。括弧内にコマンドがあり、コマンドからの出力があります。コマンドラインの一部として使用されます(二重引用符の間に置換がない限り、追加の展開の後ですが、それは別の話です)。
  • { … }中括弧は、コマンドをグループ化するという点で括弧に似ていますが、グループ化ではなく、解析にのみ影響します。プログラムx=2; { x=4; }; echo $xは4を出力しますが、x=2; (x=4); echo $xは2を出力します(また、キーワードである中括弧は区切る必要があります。コマンド位置にあります(したがって、{の後のスペースと}の前の;)括弧はありません。これは構文上の癖です。)
    • 先頭にドル記号が付いている場合、${VAR}パラメータ展開、変数の値に展開し、追加の変換が可能な場合。 ksh93シェルは、サブシェルを生成しないコマンド置換の形式として${ cmd;}もサポートします。
  • ((…))二重括弧は算術命令、つまり整数の計算を囲みます。他のプログラミング言語に似た構文。この構文は主に割り当てと条件で使用されます。これはksh / bash / zshにのみ存在し、プレーンshには存在しません。
    • 同じ構文が算術式で使用されます$((…))。式の整数値に展開されます。
  • [ … ]単一の角かっこで囲みます条件式。条件式は主に演算子(は変数が空かどうかをテストし、-e "$file"はファイルが存在するかどうかをテストします。それぞれの周りにスペースが必要であることに注意してください。演算子(例: [ "$x"="$y" ] ではなく[ "$x" = "$y" ]、および;括弧の内側と外側の両方(例:[ -n "$foo" ] [-n "$foo"] ではありません)。
  • [[ … ]]二重括弧は、ksh / bash / zshの条件式の代替形式であり、いくつかの追加機能があります。たとえば、は、ファイルが通常のファイルへのシンボリックリンクであるかどうかをテストしますが、単一の括弧には[ -L "$file" ] && [ -f "$file" ]が必要です。このトピックの詳細については、引用符のないスペースを使用したパラメーター展開が二重角かっこ[[であるが、単一角かっこではない[?]内で機能するのはなぜですか。

シェルでは、 every コマンドは条件付きコマンドです。すべてのコマンドの戻りステータスは、成功を示す0か、1〜255(一部のシェルではそれ以上)を示す整数です。失敗。 [ … ]コマンド(または[[ … ]]構文形式)は特定のコマンドであり、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 … 
  • xの値(数値と見なされる)かどうかをテストしますbash / ksh / zshで少なくとも2です:

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

コメント

  • 単一のブラケットが&&-aをサポートすることに注意してください。 / div>なので、次のように書くことができます:[ -L $file -a -f $file ]、これは括弧内の同じ文字数で、余分な[

  • @AlexisWilke演算子-a-oは関連するオペランドの一部が演算子のように見える場合、誤った解析につながる可能性があるため、問題があります。そのため、’私はそれらについて言及しません’:利点はなく、’常に機能します。また、正当な理由がない限り、引用符で囲まれていない変数展開を記述しないでください。[[ -L $file -a -f $file ]]は問題ありませんが、角かっこが1つの場合は、[ -L "$file" -a -f "$file" ]が必要です(たとえば、$fileは常に/または./で始まります。
  • 注意してください。 it ‘ s [[ -L $file && -f $file ]]-a[[...]]バリアント)。

回答

[ vs [[

この回答は、[[[の質問のサブセット。

Bash 4.3.11のいくつかの違い:

  • POSIXとBashの拡張機能:

  • 通常のコマンドと魔法

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

      ][の最後の引数です。

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

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

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

    • [[ X ]]Xを魔法のように解析する単一の構成。 <&&||()は特別に扱われ、単語分割ルールは異なります。

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

    バッシュ語の場合:[は組み込みコマンドであり、[[はキーワードです: 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 ]:ほぼ同等ですが、POSIXは非常識であるため非推奨ですaまたはbの一部の値(!またはこれは論理操作として解釈されます
  • (

    • [[ (a = a || a = b) && a = b ]]:false。 ( )がない場合、[[ && ]][[ || ]]
    • よりも優先されるため、trueになります。

    • [ ( a = a ) ]:構文エラー、()はサブシェルとして解釈されます
    • [ \( a = a -o a = b \) -a a = b ]:同等ですが、()-a、および-oは非推奨ですPOSIXによる。 \( \)がない場合は、-a-o
    • { [ a = a ] || [ a = b ]; } && [ a = b ]非推奨ではないPOSIXと同等のもの。ただし、この特定のケースでは、と&& divであるため、[ a = a ] || [ a = b ] && [ a = b ]と書くことができます。 >シェル演算子は、[[ || ]]および[[ && ]]および-o-aおよび[

  • 展開時の単語分割とファイル名生成(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( * ? [は魔法です)グロブはfに展開されません現在のディレクトリ内のファイル。
    • [ ab = a? ]a?グロブが展開されます。したがって、現在のディレクトリ内のファイルに応じて、trueまたはfalseになる可能性があります。
    • [ ab = a\? ]:false、glob拡張ではありません
    • ===は、[[[ですが、==はBash拡張機能です。
    • case ab in (a?) echo match; esac:POSIXと同等
    • [[ ab =~ "ab?" ]]:false、Bash3.2以降の""で魔法を失い、bash 3.1との互換性が有効になっていません(

    • [[ 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拡張機能の複雑さを学習させる。 [は、奇妙な名前の通常のコマンドであり、特別なセマンティクスは含まれていません。

    StéphaneChazelasの重要な修正と追加。

    コメント

    • @St é phaneChazelas情報をありがとう!’回答にexprを追加しました。用語” Bash exテンション”は、Bashが構文を追加した最初のシェルであることを意味するものではありません。POSIXshとBashを学ぶだけで、私は夢中になります。

    man [を試し、迷子になった場合。それはPOSIXバリアントを説明します。

  • 訂正:][コマンドの引数ですが、’ tはそれ以上の引数が使用されるのを防ぎます。 ][最後の引数である必要がありますが、テスト式の一部として発生することもあります。たとえば、if [ "$foo" = ] ]; thenは、変数fooが”]

    if [ ] = "$foo" ]; thenもそうです)。

  • @GordonDavissonありがとう、私は’わからない、修正済み。
  • @ tgm1024–Monicawasmistreatはい、それも有効な考慮事項です。
  • 回答

    bashドキュメントから

    (list)リストはサブシェル環境で実行されます(以下のコマンド実行環境を参照)。シェルの環境に影響を与える変数の割り当てと組み込みコマンドは、コマンドの完了後も有効ではありません。戻りステータスは、リストの終了ステータスです。

    言い換えると、「リスト」で発生したこと(cdなど)が(以外では効果がないことを確認します。 )。リークするのは、最後のコマンドの終了コード、またはエラーを生成する最初のコマンドのset -eだけです(その他ifwhileなどのいくつかよりも)

    ((expression))式は、以下のARITHMETIC EVALUATIONで説明されているルールに従って評価されます。式の値がゼロ以外の場合、戻りステータスは0です。それ以外の場合、戻りステータスは0です。は1です。これは、let ” expression “とまったく同じです。

    これは、数学を実行できるbash拡張機能です。これは、exprのすべての制限(どこにでもスペースがある、iv id = “314ea96a82″をエスケープするなど)なしでexprを使用するのと多少似ています。 >

    など)

    [[ expression ]]ステータスに応じて、0または1を返します。条件式式の評価。式は、以下の条件式で説明されているプライマリで構成されています。 [[と]]の間の単語に対して、単語の分割とパス名の展開は実行されません。チルダ展開、パラメーターおよび変数展開、算術展開、コマンド置換、プロセス置換、および引用符の削除が実行されます。 -fなどの条件演算子は、プライマリとして認識されるために引用符で囲まれていない必要があります。

    [[、<および>演算子は現在のロケールを使用して辞書式に並べ替えます。

    これは、

    オファーですが、より強力です。

    [ expr ]ステータスを返します。条件式exprの評価に応じて、0(true)または1(false)。各演算子と演算子は、個別の引数である必要があります。式は、上記の「条件付き式」で説明したプライマリで構成されます。 testはオプションを受け入れません。また、オプションの終わりを示す-の引数を受け入れて無視しません。

    […]

    これはtestを呼び出します。実際、昔は[testへのシンボリックリンクでした。それは同じように機能し、同じ制限があります。バイナリは開始された名前を知っているので、テストプログラムはそれがいつ開始されたかを[として認識し、最後のパラメータを無視できます。これは]。楽しいUnixのトリック。

    bashの場合、[およびtestは(コメントに記載されているように)組み込み関数ですが、ほぼ同じ制限が適用されます。

    コメント

    • ただしtest[はもちろんBashに組み込まれているコマンドですが、’は外部バイナリも存在します。
    • [の外部バイナリは、ほとんどの最新システムのtestへのシンボリックリンクではありません。 。
    • どういうわけか、単に組み合わせていくつかの条件を追加するのではなく、2つの別々のバイナリを作成するのが面白くて、どちらも必要なものだけを持っています。実際にはstrings /usr/bin/testにヘルプテキストも表示されているので、’何を言うべきかわかりません。
    • @ Random832予期しないarg0の動作を回避するためのGNUの理論的根拠についてはあなたの意見を聞きますが、POSIXの要件については、’それほど肯定的ではありません。 testコマンドは、標準ではスタンドアロンのファイルベースのコマンドとして存在する必要があることは明らかですが、その[バリアントが必要であるとは何も述べていません。そのように実装することもできます。たとえば、Solaris11は’実行可能ファイルを[提供していませんが、それでもPOSIX標準に完全に準拠しています
    • (出口1)は括弧の外に影響を及ぼします。

    回答

    いくつかの例:

    従来のテスト:

    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 ... 

    “通常”commands:

    上記はすべて通常のコマンドのように機能し、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 ... 

    回答

    グループ化コマンド

    Bashには、実行するコマンドのリストを1つの単位としてグループ化する2つの方法があります。

    ( list )コマンドのリストを括弧で囲むと、サブシェル環境が作成され、リスト内の各コマンドがそのサブシェルで実行されます。サブシェルで実行されると、サブシェルが完了した後、変数の割り当ては有効になりません。

    $ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a" inside: a=2 outside: a=1 

    { list; }中括弧で囲まれたコマンドのリストにより、リストは現在のシェルコンテキストで実行されます。サブシェルは作成されません。次のリストのセミコロン(または改行)が必要です。 ソース

    ${} Parameter expansion Ex: ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s $() Command substitution Ex: result=$(COMMAND) $(()) Arithmetic expansion Ex: var=$(( 20 + 5 )) 

    条件付き構文

    シングルブラケットすなわち[]
    比較のために==, !=, <,および>であり、数値比較のためにeq, ne,ltおよびgtを使用する必要があります。

    拡張ブラケットつまり[[]]

    上記のすべての例では、条件式を囲むために単一の角かっこのみを使用しましたが、bashでは、単一の角かっこ構文の拡張バージョンとして機能する二重の角かっこを使用できます。

    比較のために、==, !=, <,>は文字通り使用できます。

    • [はtestコマンドの同義語です。シェルに組み込まれている場合でも、新しいプロセスが作成されます。
    • [[は、プログラムではなくキーワードである、新しい改良版です。 。
    • [[KornBashによって理解されます。

    ソース

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です