パイプ処理の終了ステータスを取得する | Linux shell

パイプ処理の終了ステータスを取得する方法をまとめます。

はじめに

おはよう。@bioerrorlogです。

パイプ処理の終了ステータスを取得($?)すると、デフォルトでは一番最後のコマンドの終了ステータスのみが取得されます。

#!/bin/bash

exit 1 | exit 2 | exit 0
echo $? # 出力: 0

パイプ内コマンドの終了ステータスはマスクされてしまうので、パイプ内の異常終了を検知したいときなどに不都合です。

今回は、パイプ処理内の各コマンドの終了ステータスを取得する方法をまとめます。

環境

bashでの実行を前提としています。

パイプ処理の終了ステータスを取得する

PIPESTATUS を参照する方法

まずは、PIPESTATUSを使った方法です。 この変数には、実行されたパイプ処理内コマンドの終了ステータスが配列で格納されます。

${PIPESTATUS[@]}で参照すれば、パイプ処理内の全コマンドの終了ステータスが確認できます。

#!/bin/bash

exit 1 | exit 2 | exit 0
echo "${PIPESTATUS[@]}" # 出力: 1 2 0


引数を渡して参照すれば、特定のパイプ処理内コマンドの終了ステータスを取得できます。

#!/bin/bash

exit 1 | exit 2 | exit 0
echo "${PIPESTATUS[0]}" "${PIPESTATUS[1]}" # 出力: 1 2

set -o pipefail を利用した方法

次はset -o pipefailを利用した方法です。

set -o pipefailは、0以外の終了ステータスで終えた最後のコマンドの終了ステータスを、パイプ処理の終了ステータスとする設定です。 パイプ内コマンドの異常終了ステータスをマスクせずに取得することが出来るようになります。

setコマンドのman pageより引用:

the return value of a pipeline is the status of the last command to exit with a non-zero status, or zero if no command exited with a non-zero status


実際に実行してみると、以下のようにパイプ内の最後の異常終了ステータスが、パイプの終了ステータスとして取得されます。

#!/bin/bash

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

おわりに

今回は、パイプ処理の終了ステータスを取得する方法をまとめました。

パイプ処理は非常に強力な機能なので、細かいハンドリングも含めて使い慣れていきたいものです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

参考

shell - Get exit status of process that's piped to another - Unix & Linux Stack Exchange

set -e, -u, -o, -x pipefail explanation · GitHub

set man page