Going Faraway

渡辺遼遠の雑記帳。技術ネタと読んだ本の紹介。

Bashでパイプされたコマンドの出力を変数に割り当て、同時に戻り値を調べる方法

ぐぐってもあまり情報が出てこなかったのでメモ。

Bashで 「$?」を使えば実行したコマンドの戻り値が取得できるのは有名。

$ false; echo $?
1 # falseの戻り値

Bashの場合、パイプされたコマンドの戻り値は 「PIPESTATUS」という配列に格納されることも、それなりに知られていると思う。

$ true | true | false
$ echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
0 0 1 # true, true, falseの戻り値

ところが、バッククオートや 「$()」 によるコマンド置換の中で複数のコマンドをパイプし、その出力を何らかの変数に割り当て、かつ戻り値を調べようとするとうまく行かない。

RESULT=$( some_command | false | true )
echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
0 # 最後のtrueの戻り値
RESULT=$( some_command | false | true | false )
echo ${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]}
1 # 最後のfalseの戻り値

上記の通り、コマンド置換中の最後のコマンドの戻り値以外は取得できない。
これは、コマンド置換がサブシェルを作成するものであり、PIPESTATUS 配列はそのサブシェル (コマンド置換内) でしか使用できないために起こるのだそうだ。

コマンド置換内のコマンドのうち、1件のみ (今の例ではsome_command) の戻り値が知りたいだけであれば、コマンド置換の中で exit statusを返してやれば良い。

RESULT=$( some_command | false | true | false; exit ${PIPESTATUS[0]} )
echo $?
0 # some_command の戻り値