戻り値を取得する際は通常「$?」を使用しますが、パイプを使用している場合は正しく取得出来ません。今回はパイプ使用時に正しい戻り値を取得する方法を説明します。
$? を使用した場合の動き
$? を使用して戻り値を取得した例です。
下記のように、$?を使用して取得した場合、
パイプの一番最後に実行したコマンド(一番右のコマンド)の結果が取得されてしまいます。
#!/bin/bash
exit 2 | exit 1 | exit 0
echo 戻り値:$?
戻り値:0
#!/bin/bash
exit 3 | exit 2 | exit 1
echo 戻り値:$?
戻り値:1
パイプしたコマンド全ての戻りを取得
システム変数「PIPESTATUS」を使用することで、下記のようにパイプした全てのコマンドを戻り値を取得することが可能です。
#!/bin/bash
exit 3 | exit 2 | exit 1
echo 戻り値:${PIPESTATUS[@]}
戻り値:3 2 1
パイプ中の指定したコマンドの戻り値を取得する
システム変数「PIPESTATUS」は配列になっているため、配列を添字で指定することで各コマンドの戻り値を取得することが可能です。
#!/bin/bash
exit 3 | exit 2 | exit 1
echo 戻り値:${PIPESTATUS[1]}
戻り値:2
パイプしたコマンドの終了判定①
パイプされた全てのコマンドが正常終了、または1つでも異常終了した場合の判定方法になります。
全てのコマンドが正常終了(戻り値[0])の場合は、「OK」と表示されます。
#!/bin/bash
exit 0 | exit 0 | exit 0
if [[ `echo ${PIPESTATUS[@]} | sed -e "s/0 //g"` == 0 ]];
then
echo OK
else
echo NG
fi
1つでも異常終了(戻り値が[0]以外)がある場合は、「NG」と表示されます。
#!/bin/bash
exit 0 | exit 1 | exit 0
if [[ `echo ${PIPESTATUS[@]} | sed -e "s/0 //g"` == 0 ]];
then
echo OK
else
echo NG
fi
パイプしたコマンドの終了判定②
下記のように変数に値を格納し、そこから判定することも可能です。
パイプの全コマンドが正常終了するパターンです。「OK」が表示されます。
#!/bin/bash
exit 0 | exit 0 | exit 0
rc=${PIPESTATUS[@]}
if [[ `echo ${rc//0 /}` == 0 ]];
then
echo OK
else
echo NG
fi
パイプのコマンドで異常終了があるパターンです。「NG」が表示されます。
#!/bin/bash
exit 0 | exit 1 | exit 0
rc=${PIPESTATUS[@]}
if [[ `echo ${rc//0 /}` == 0 ]];
then
echo OK
else
echo NG
fi
パイプしたコマンドの終了判定③
「pipefail」を有効化することで、パイプしたコマンドの戻り値を取得することが可能です。
異常終了したコマンドが単一の場合は、そのコマンドの戻り値が取得されます。
#!/bin/bash
set -o pipefail
exit 0 | exit 99 | exit 0
echo 戻り値:$?
戻り値:99
異常終了したコマンドが複数の場合は、異常終了したコマンドのうち、最後のコマンドの戻り値が取得されます。
#!/bin/bash
set -o pipefail
exit 2 | exit 1 | exit 0
echo 戻り値:$?
戻り値:1
記事は以上となります。
コメント