背景
たとえば、
$ true | false | true
や
$ ls -S1 hoge* | haed -n1
の様なパイプ処理を含んだシェルスクリプトを動作させた直後に、
$ echo $?
などのコマンドでステータスコードを確認したとき、最初や途中の処理でエラーが発生していたとしても、パイプの最後のステータスコードしか取得出来ない。
途中経過のステータスコードを取得する際には、実行直後に、${PIPESTATUS[@]}という配列を参照することで得ることが出来る。
$ true | false | true
$ echo ${PIPESTATUS[@]}
0 1 0
Fabric の場合
通常、Fabric の場合には、runコマンドや sudoコマンドなどの戻り値に.succeededや.failedなどというプロパティがあるので、これを参照することが多い。
result = run("false", warn_only=True)
print result.succeeded
ただし、${PIPESTATUS[@]}に相当する変数はないため、途中でのステータスコードは取得出来ない。
問題点
冒頭のシェルスクリプトの様な例を考える。
@task
def return_test():
# カレントディレクトリの hoge という文字列を含むファイルのなかで一番大きいものを表示する
result = run("ls -S1 *hoge* | head -n1")
print result.succeed
print result
このときに、カレントディレクトリに hoge を含むファイル/ディレクトリがない場合には、.succeededはrunの結果しか返しないし(headは実行出来ているので、ここはTrue)、内容としてはエラーの表示(標準エラー出力)がそのまま返ってしまう。
[192.168.0.1] Executing task 'return_test'
[192.168.0.1] run: ls -S1 *hoge* | head -n1
[192.168.0.1] out: ls: cannot access *hoge*: No such file or directory
[192.168.0.1] out:
True
ls: cannot access *hoge*: No such file or directory
Done.
Disconnecting from 192.168.0.1... done.
本来欲しい情報が返っているわけではないし、気持ち悪いのだけど、この例だとたまたまそういうディレクトリ名なのかも知れない場合もあるし困る。
解決法(結論)
お茶を濁しましょう。
@task
def return_test():
result = run("ls -S1 *hoge* 2> /dev/null | head -n1")
print result
[192.168.0.1] Executing task 'return_test'
[192.168.0.1] run: ls -S1 *hoge* 2> /dev/null | head -n1
Done.
Disconnecting from 192.168.0.1... done.