パイプの優先順位(|)およびbashの論理および(&&)


17

演算子の優先順位を持つ古典的なシナリオには、次のような行があります。

(cd ~/screenshots/ && ls screenshot* | head -n 5)

そして、それが解析されているの((A && B) | C)か、それとも(A && B | C)...

ここにあるほぼ公式のドキュメントは、リストにパイプがリストされていないため、単純にテーブルをチェックインすることはできません。

さらに、bashでは、(操作の順序を変更するだけでなく、サブシェルを作成するため、この行が前の行と同等であることを100%確信していません:

((cd ~/screenshots/ && ls screenshot*) | head -n 5)

より一般的には、bash行のASTを知る方法は?pythonには、操作の順序を簡単に再確認できるように、ツリーを提供する関数があります。


1
これは|、LHS標準出力をRHS標準入力に適合させる単なるコネクタであることを知るのに役立つかもしれません。もしそうならcd、あなたの例では、コマンドが失敗し、それはへの出力を送信しないだろうheadが、headまだ実際に考えexecute、何を解析しないと、何も出力を返しません。
-DopeGhoti


1
bashアドホックなものではなく、yacc パーサーを使用しています。それを実行すると、yacc -vそれy.outputを示してリスト&&||結合する素晴らしい文法が得られ、リストは最終的にパイプラインで構成されます(逆ではありません)。tl; dr; 予想どおりA && B | C、と同じA && { B | C; }です。Bとの間の実行順序を想定しないでくださいC。パイプラインのコマンドは並行して実行されます
mosvy

1
あなたが指す「ほぼ公式の文書」は、[...]テストや$((...))算術評価の中で使用される演算子に関するものであるため、完全に無関係です。特に、||そして&&シェル言語のコマンドリストで使用されるように持って、同じ優先順位の各演算子とは異なり、C(又は算術評価に&&結合するより強固より||)。
mosvy

@mosvy、そのドキュメントはテーブルがどのコンテキストに適用されるかさえも述べていないので、その意味でもあまり役に立たないようです
...-ilkkachu

回答:


20
cd ~/screenshots/ && ls screenshot* | head -n 5

これは次と同等です

cd ~/screenshots && { ls screenshot* | head -n 5 ; }

中括弧はサブシェルなしでコマンドをグループ化します)。したがって、の優先順位はおよび|よりも高くなります(バインドが厳しく&&なり||ます)。あれは、

A && B | C

そして

A || B | C

常にBの出力のみがCに与えられることを意味します。(...)または{ ... ; }を使用して、必要に応じて明確化のためにコマンドを単一のエンティティとして結合できます。

{ A && B ; } | C
A && { B | C ; } # This is the default, but you might sometimes want to be explicit

いくつかの異なるコマンドを使用して、これをテストできます。走ったら

echo hello && echo world | tr a-z A-Z

その後、あなたは得るでしょう

hello
WORLD

戻る:tr a-z A-Z入力を大文字にし、それだけecho worldでパイプされていることがわかりますecho hello


これがに定義されたシェルの文法:ひどくはっきりしていないが、and_or(のための生産は&&/ ||)AAを持つように定義されてpipelineいる間、その本体にpipelineだけ含まれcommandている、いない含まれているand_or-唯一のcomplete_command生産が到達することができand_or、そしてそれだけで存在していますトップレベルで、関数やループなどの構造的な構造の本体の内部。

その文法を手動で適用してコマンドの解析ツリーを取得できますが、Bashはそれ自体を提供しません。自分の解析に使用されているものを超えて機能するシェルについては知りません。

シェルの文法には、半形式的にのみ定義された多くの特殊なケースがあり、正しく処理することは非常に重要です。Bash自体でさえ間違っていることがあるため、実用性と理想は異なる場合があります。

構文を一致させてツリーを生成しようとする外部パーサーがありますが、その中で最も信頼性の高いMorbigをお勧めします。


7

TL; DR:などの区切り文字をリストし;ます。&&&、および||解析順序を決めます。

bashのマニュアルを教えてくれる:

ANDおよびORリストは、&&および||で区切られた1つ以上のパイプラインのシーケンスです。それぞれ制御演算子。

または、Bash Hackerのwikiが簡潔にそれをどのように置いたか

<PIPELINE1> && <PIPELINE2>

したがって、cd ~/screenshots/ && ls screenshot* | head -n 5 1つのパイプラインls screenshot* | head -n 5と1つの単純なコマンドがありcd ~/screenshots/ます。マニュアルに従って

パイプラインの各コマンドは、個別のプロセスとして(つまり、サブシェルで)実行されます。

一方、(cd ~/screenshots/ && ls screenshot*) | head -n 5異なる-パイプラインが1つありますhead -n 5。左側にサブシェルがあり、右側にがあります。この場合、OPの表記法を使用すると次のようになります。(A && B) | C


別の例を見てみましょう。

$ echo foo | false &&  echo 123 | tr 2 5
$

ここに1つのリストがあり<pipeline1> && <pipeline2>ます。パイプラインの終了ステータスは最後のコマンドの終了ステータスと同じであり、falseネガティブステータス、つまり失敗を返すことがわかっている&&ため、右側を実行しません。

$ echo foo | true &&  echo 123 | tr 2 5
153

ここでは、左側のパイプラインに成功の終了ステータスがあるため、右側のパイプラインが実行され、その出力が表示されます。


シェルの文法は実際の実行順序を意味するものではないことに注意してください。ジルの答えの 1つを引用するには:

パイプコマンドは同時に実行されます。psを実行するとき| grep…、それはpsまたはgrepが最初に開始するかどうか、そしていずれにせよ続行するかについてのドローの運(またはカーネルの腸の奥深くでスケジューラーの微調整と組み合わされたシェルの動作の詳細の問題)同時に実行します。

そして、bashマニュアルから:

ANDおよびORリストは左結合で実行されます。

その中に基づいて、最初に実行されるだろう前のコマンドが成功した場合、しかし、最初のプロセスではなく生み出される彼らはパイプラインにあるので。cd ~/screenshots/ && ls screenshot* | head -n 5cd ~/screenshots/ls screenshot* | head -n 5head -n 5ls


1
質問がどこで発生するのかについて何が尋ねられるのかわかりません。
マイケルホーマー

「最初に生成される優先順位はありません」cd ~/screenshots/ && ls screenshot*またはhead -n 5ええ、はい、そう((cd ~/screenshots/ && ls screenshot*) | head -n 5)です。しかし、それはcd ~/screenshots/ && ls screenshot* | head -n 5質問のポイントであると思われる曖昧なケースについては何も言っていません(括弧を囲むかどうかにかかわらず)。
-ilkkachu

@ilkkachuその通りですが、次の文章がそれに触れます。リストは優先順位が高いため(少なくともl0b0の回答に基づいて)、cd ~/screenshots/ && ls screenshot* 最初に処理する必要があります&&。どこで答えを改善すべきだと思いますか?
セルギーKolodyazhnyy

@SergiyKolodyazhnyyも、質問にとの両方があることを考える(cd && ls | head)((cd && ls) | head)、どちらを意味するのかを明示するのが良いかもしれません。
-ilkkachu

@ilkkachu OK、今のところこれを削除し、その間に編集します
セルギー・コロディアズニー

3

で指定する場所はbash(1)次のとおりです。

SHELL GRAMMAR
[...]
   Pipelines
       A  pipeline  is  a sequence of one or more commands separated by one of
       the control operators | or |&.
[...]
   Lists
       A list is a sequence of one or more pipelines separated by one  of  the
       operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or
       <newline>.

そのため、&&パイプラインを分離します。


2

あなただけを試すことができecho hello && echo world | lessます。|優先順位が高いことがわかります(コマンドのパイプラインはコマンドです)。2番目の例では同じではありません。ただし、cd出力がないため、違いはありません。

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