LoginSignup
19
16

More than 3 years have passed since last update.

パイプしたときの終了ステータスの取得方法

Posted at

コマンドの実行でエラーが起こってないか監視ツールで監視したいため、
コマンドの実行が成功したか失敗するか取得する方法を調べました。

正常 or エラー

Linux(Unix)では、すべてのコマンドは終了コード(exit code)を返します。
0が成功、1以上の値はエラーです。
エラー時の終了ステータスは以下のように予約されています。
128+nのエラー内容はコマンドやソフトウェアの実装によって異なります。

終了ステータス 意味
1 一般的なエラー
2 ビルトインコマンドの誤用
126 コマンドを実行できなかった(実行権限がなかった)
127 コマンドが見つからなかった
128 exit に不正な値を渡した(例えば浮動小数点数)
128+n シグナル n で終了
255 範囲外の終了ステータス

引用:
https://ja.wikipedia.org/wiki/%E7%B5%82%E4%BA%86%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9#bash

特殊変数 $?

直前に実行したコマンドの終了コードは$?という特殊変数に格納されています。
echo $?というコマンドを実行することで直前の終了コードを表示できます。
echoは引数の文字列や変数を表示するコマンドです。

パイプの終了ステータス

# exit 2 | exit 1 | exit 0

こういうケース。
3つのコマンドをパイプで繋いでいます。
1つめと2つめはエラーを返すようになっています。

上記のコマンドの実行後にecho $?とすると、0(正常終了)が返ってしまいました。

パイプ元でエラーが発生していても正常終了扱いになってしまうので注意が必要です。
(たぶん、最後に終了したコマンドの終了コードが帰ってきます。)

簡単な解決策は2つあります。
ただし、Bash,Zsh以外のシェルでも使えるか不明なので注意すること。

PIPESTATUS

# exit 2 | exit 1 | exit 0
# echo  ${PIPESTATUS[@]}
2 1 0

PIPESTATUSという配列変数で取得できます。

set -o pipefail

pipefailを有効にすると、Pipeでエラーが有ったときそのエラーコードを返してくれます。

# set -o pipefail
# exit 2 | exit 1 | exit 0
# echo $?
2

関連:リダイレクトの終了ステータス

リダイレクト元かリダイレクト先のどちらかが終了ステータスを返したら
その終了ステータスを返します。

# echo aaa > .
# echo $?
1

#  cat . > file.txt
# echo $?
1

.はディレクトリなので、書き込めずエラーになります。

19
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
16