質問はタイトルにあります。感嘆符で始まるシェルコマンド(シェルスクリプトの一部)の目的は何ですか?具体例:
foo.sh:
#!/usr/bin/env bash
set -e
! docker stop foo
! docker rm -f foo
# ... other stuff
スペースがないと、感嘆符が履歴の置換に使用され、 man page に従って! <expression>
を使用して、「exprがfalseの場合はtrue 」。しかし、私にとって意味をなさない例のコンテキストでは。
TL; DR:これは、使用している特定の行のset -e
フラグをバイパスするだけです。
hek2mglの正解および有用な回答 にaddを追加します。
あなたが持っている:
set -e
! command
パイプラインの各コマンドは、独自のサブシェルで実行されます。パイプラインの終了ステータスは、パイプラインの最後のコマンドの終了ステータスです(...)。予約語「!」がパイプラインの前にある場合、終了ステータスは上記のように終了ステータスの論理否定です。シェルは、パイプライン内のすべてのコマンドが終了するのを待ってから値を返します。
これは、コマンドの前の!
が終了ステータスを無効にしていることを意味します。
$ echo 23
23
$ echo $?
0
# But
$ ! echo 23
23
$ echo $?
1
または:
$ echo 23 && echo "true" || echo "fail"
23
true
$ ! echo 23 && echo "true" || echo "fail"
23
fail
終了ステータスは、多くの点で役立ちます。スクリプトでset -e
と共に使用すると、コマンドがゼロ以外のステータスを返すたびにスクリプトが終了します。
したがって、次の場合:
set -e
command1
command2
command1
がゼロ以外のステータスを返す場合、スクリプトは終了し、command2
に進みません。
ただし、 4.3.1 The Set Builtin で説明されている興味深い点もあります。
-e
単一の単純なコマンド(単純なコマンドを参照)、リスト(リストを参照)、または複合コマンド(複合コマンドを参照)で構成されるパイプライン(パイプラインを参照)がゼロ以外のステータスを返す場合、すぐに終了します。シェルは終了しませんwhileまたはuntilキーワードの直後のコマンドリストの一部、ifステートメントのテストの一部、anyの一部&&または||で実行されるコマンド最後の&&または||に続くコマンド、パイプライン内の最後のコマンド以外のコマンド、またはコマンドの戻りステータスが!で反転している場合を除くリスト。サブシェル以外の複合コマンドが、-eが無視されている間にコマンドが失敗したためにゼロ以外のステータスを返す場合、シェルは終了しません。 ERRのトラップは、設定されている場合、シェルが終了する前に実行されます。
次の場合、これらすべてを考慮に入れてください。
set -e
! command1
command2
あなたがしているのは、set -e
のcommand1
フラグをバイパスすることです。どうして?
command1
が正常に実行されると、ゼロのステータスが返されます。 !
はそれを無効にしますが、set -e
は、上記のように!で反転された戻りステータスから来るため、終了をトリガーしません。command1
が失敗すると、ゼロ以外のステータスを返します。 !
はそれを無効にするため、行は最終的にゼロのステータスを返し、スクリプトは通常どおり続行されます。コマンドのエラーまたは成功の両方の場合にスクリプトを失敗させたくない場合は、この代替手段も使用できます。
set -e
docker stop foo || true
ブール値またはtrueを指定すると、パイプラインの戻り値は常に0
になります。
「!」 「しない」という意味なので、コマンドの前に配置して「$?」を実行するとこれは1をエコーします。つまり、成功を意味する0の代わりに失敗を意味します。