私はbashのソースコードを読んでおり、bashの BNF文法 は次のようになります。
<pipeline_command> ::= <pipeline>
| '!' <pipeline>
| <timespec> <pipeline>
| <timespec> '!' <pipeline>
| '!' <timespec> <pipeline>
<pipeline> ::=
<pipeline> '|' <newline_list> <pipeline>
| <command>
これは、!
コマンドも一種のパイプであることを意味しますか?.
! ls
は機能しますが、ls
と同じです。
! time ls
も機能します。
これは|
パイプとはかなり異なります。
Bashで!
を使用する方法パイプですか?
Bashマニュアルから:「予約語!がパイプラインの前にある場合、そのパイプラインの終了ステータスは終了ステータスの論理否定です」
あなたは文法を誤解しています。文法が言っているのは、!パイプラインの前で、置き換えないでください。とともに !。
感嘆符は、コマンド/パイプラインの戻りコードを論理的に逆にします(例: Bashのマニュアル を参照):
if true ; then echo this prints ; fi
if ! false ; then echo this also prints ; fi
if ! true ; then echo this does not print ; fi
パイプラインの戻りコードは(通常)直前のコマンドの戻りコードに過ぎないため、強打すると次のようになります。
if ! true | false ; then echo again, this also prints ; fi
パイプラインをone以上のコマンドとして定義すると、実際にはパイプを含まないものの、単一のコマンドもパイプラインになります。利点は、否定演算子としての!
をコマンドとパイプラインに個別に定義する必要がないことです。パイプラインに適用するものとして定義する必要があるだけです。
! cmd1 | cmd2
では、!
は、単一のコマンドcmd1
だけでなく、パイプライン全体の終了ステータスを無効にします。パイプラインの終了ステータスは、デフォルトでは、右端のコマンドの終了ステータスです。
同様に、listは、;
、&
、&&
、または||
で結合されたもう1つのパイプラインです。したがって、単一のパイプラインもリストであり、単一のコマンドもリストです。次に、if
のようなコマンドがif
とthen
キーワードの間のリストをとるように定義されている場合、これは自動的に単一のコマンドと単一のパイプラインを定義の一部として含みますコマンド。
2つのパイプラインで構成されるリスト(そのうちの1つは1つのコマンドのみで構成されます):
if IFS= read -r response && echo "$response" | grep foo; then
単一のパイプラインで構成されるリスト:
if echo "$foo" | grep foo; then
単一のパイプライン(それ自体が単一のコマンドのみを含む)で構成されるリスト:
if true; then
他の回答が言ったことに追加するいくつかのポイント:
chepner’s answer によって(間接的に)記述されているように、_!
_演算子は、_<pipeline_command>
_ではなく_<command>
_構文要素のオプションの接頭辞として定義されます。これはあなたが言うことができないという結果を持っています
_ cmd1 | ! cmd2
_
または
_! cmd1 | ! cmd2
_
「パイプライン全体」の終了ステータスのみを無効にすることができます。 chepnerが指摘したように、「パイプライン」は単一のコマンドにすることができるため、次のようなことができます
_! cmd1 && ! cmd2; ! cmd3 || ! cmd4
_
しかし、それはばかげています。 _!
_の前の_cmd2
_は、何もしません。 _!
_の前の_cmd4
_は、コマンドの最後にある_$?
_の値にのみ影響し、他の2つはANDとORを交換することで削除できます。
_ cmd1 || cmd2; cmd3 && cmd4
_
同様に、_while ! cmd
_は_until cmd
_に置き換えることができます。
_<pipeline>
_が前に付いた_!
_は、_<pipeline_command>
_になります—別の構文要素です。したがって、それは言うことは有効ではありません
_! ! cmd1
_
算術展開とは異なり、$((! ! value))
や$((! ! ! value))
などが有効です。
[〜#〜] posix [〜#〜] は同じ文法を定義しますが、異なる要素名を使用することに注意してください。質問のBNFは、POSIXでは次のように表示されます
_pipeline : pipe_sequence
| Bang pipe_sequence
pipe_sequence : command
| pipe_sequence '|' linebreak command
_
ここで、Bang
は_%token
_の値を持つ_'!'
_です。