コマンドが実行された後、終了コードがbashによって設定されているのか、それとも実行されたコマンドで設定されているのかをどうやって確認できますか?

コマンドが実行された後、終了コードがbashによって設定されているのか、それとも実行されたコマンドで設定されているのかをどうやって確認できますか?

私のbashの知識は少し錆びていて(以前はそれほど堅牢ではなかった)、次の質問に対する答えが見つからないようです。

タイトルが示すように、コマンドが実行された後にbashによってゼロ以外の終了コードが設定されているかどうかを確認する方法を知りたいです。本物エラー)またはコマンドを介して(可能コマンドと目的に応じてエラーを示します。

たとえば、次のような非常に単純なスクリプトを見てみましょう。

#!/bin/bash

string='abc'
grep 'd' <<< "$string"
echo $?

これはマニュアルを読んgrepだ後に予想される1を出力します(抜粋、短縮された鉱山)。

終了状態
通常、終了状態は行が選択されている場合は0、選択された行がない場合は1、エラーが発生した場合は2です。 [...]

bashマニュアルの該当するセクションを読んだ後に問題が発生しました(私は抜粋、短縮、強調)。

終了ステータス

[...]

コマンドが見つからない場合、コマンドを実行するために生成されたサブプロセスは状態127を返します。コマンドが検出されたが実行可能でない場合、戻り状態は 126 です。

拡張またはリダイレクト中にエラーが原因でコマンドが失敗した場合、終了ステータスは0より大きくなります。

シェル組み込みコマンドは成功するとステータス0(true)を返し、実行中にエラーが発生した場合は0以外の値(false)を返します。すべての組み込み関数は終了状態2を返し、誤った使用法、通常は無効なオプション、または欠落している引数を示します。

[...]

私の質問は強調された声明です。

grep私のスクリプトは通常、実際のエラー(権限の欠如、必要なプログラムが利用できない、リソースの枯渇など)を具体的に処理する必要がありますが、上記の例では行が選択されていない場合、上記の意味ではエラーではありません。これは、単に入力に一致する文字シーケンスが含まれていないことを意味します。

bashただし、マニュアルの一部を文字通り受け入れると、終了bash状態自体を設定することもできます1。このセクションでは、コマンドが見つからない(exit status 127)または実行できない場合(exit status)、126何が起こるかを知ることができます。

私が理解しているように、そのセクションの次のステートメントは、他のすべてのエラーが[1, 255]bashを介して包含範囲内のすべての終了状態にマッピングできることを意味します。特に、これは終了状態にマッピングできます1。私は「コマンドが見つかりません」や「コマンドを実行できません」に加えて、多くのエラーがあると信じているので、これを主な問題と考えています。たとえば、メモリの消耗、ファイルハンドルの消耗、ディスク読み取りエラーによるタイムアウトなどにより、コマンドの実行がブロックされる可能性があります。

"grep が一致する行が見つかりません。"エラーと比較すると、次のようになります。本物重大なエラーのため、通常、即時処置のために管理者に電子メールが送信されます。

ただし、2つのエラー(コマンドを実行して設定されたゼロ以外の終了状態とコマンドを実行しようとした後にbashが設定したゼロ以外の終了状態)を区別できないようです。

誰でも私に合理的な解決策を教えてもらえますか?

エマルジョン

研究中に同様の問題がたくさん発生しました。しかし、私が知っている限り、そのような人は誰もいません。精密同じ質問。

代わりに、ほとんどの人はただコマンドによって返されるゼロ以外の終了コードを抑制します。(私の例に適用すると、行が選択されていないときの状態ではなく0終了状態が必要でした)同様の解決策が得られました。1grepcommand || true

これは彼らには受け入れられますが、私にとっては解決策ではありません。本物上記のエラーです。たとえば、次の状況を考えてみましょう。

root@cerberus:~/scripts# { ThisProgramDoesNotExist 2>/dev/null || true; } && { echo "Gotcha!"; }
Gotcha!
root@cerberus:~/scripts#

これは、このソリューションが実行コマンドのゼロ以外の終了状態(または「stati」ですか?)だけでなく、起動コマンドが失敗したときにbashが報告する致命的なエラーも抑制する方法を示しています。これはほとんどのスクリプトでは許可されていません。

ベストアンサー1

あなたは言うことができません。あなたが得ることは0から255の間の単一値です。すべてがうまくいけばゼロ、そうでなければゼロではありません。

ゼロ以外の状態を成功と見なすには、関連コマンドが他の理由(リダイレクトなど)で失敗しないことを確認してください。さまざまな種類のエラーが複数のコマンドで発生するか、異なる状態が発生するようにコマンドを分類します。

たとえば、エラーがリダイレクトによって発生したかどうかを知る必要がある場合は、別のコマンドでリダイレクトを実行したり、ブロックを介して個別にリダイレクトを実行したりできます。

全体的な状態:

mycommand <foo
status=$?
if [ $status -ne 0 ]; then echo "Either mycommand failed or <foo failed"; fi

別の状態ですが、リダイレクトが失敗した場合にコマンドの実行を回避する方法はありません。

{
  mycommand
  command_status=$?
} <foo
redirection_status=$?
if [ $command_status -ne 0 ]; then echo "mycommand failed"; fi
if [ $redirection_status -ne 0 ]; then echo "<foo failed"; fi

まず、リダイレクトを実行します。このようにリダイレクト失敗に対応できるのはbashの機能です。組み込みリダイレクトが失敗すると、execPOSIXシェル(POSIXモードのbashを含む)が終了します。

exec 3<&1         # Save stdin to file descriptor 3
exec <foo         # bash keeps going if the redirection fails
redirection_status=$?
mycommand
command_status=$?
exec <&3          # Restore stdin
if [ $command_status -ne 0 ]; then echo "mycommand failed"; fi
if [ $redirection_status -ne 0 ]; then echo "<foo failed"; fi

リダイレクトが失敗した場合は、事実の後にファイル記述子を復元することなく、サブシェルにリダイレクト失敗を含めます。

(
  exec <foo || exit $?     # In POSIX sh, "|| exit $?" is redundant.
  mycommand
  command_status=$?
  if [ $command_status -ne 0 ]; then echo "mycommand failed"; fi
)
redirection_status=$?
if [ $redirection_status -ne 0 ]; then echo "<foo failed and mycommand didn't run"; fi

エラーが別の拡張機能で発生するかどうかを確認する必要がある場合は、別々の拡張機能を実行して結果を保存してください。

パラメータの保存: `mycommand "$(…)" の代わりに拡張結果を最初に保存します。

foo=$(…) && mycommand "$foo"

より一般的に:

foo=$(…)
command_substitution_status=$?
mycommand "$foo"
mycommand_status=$?

割り当てに複数のコマンド置換が含まれる場合、その状態は最後の置換の状態です。最後の置換が成功すると、前の置換が失敗しても状態はゼロです。

foo=$(…)
foo_status=$?
bar=$(…)
bar_status=$?
mycommand "$foo" "$bar"
mycommand_status=$?

複数のパラメータを保存するには、関数内で配列または位置パラメータを使用します。

args=()
foo=$(…)
foo_status=$?
args+=(-x "$foo")
bar=$(…)
bar_status=$?
args+=(-y "$bar")
mycommand "${args[@]}"

おすすめ記事