2013-07-21 20 views
5

をbashで使用している場合、バックティックの内部でいくつかのコマンドをパイプで実行すると、最初のコマンドの終了ステータスをどのように調べることができますか?bash pipestatusコマンドの逆戻り?

つまり、この場合、「1」を取得しようとしています。 、私が達成しようとしているより一般的に

## PIPESTATUS[0] works to give me the exit status of 'false': 
$ false | true; 
$ echo $? ${PIPESTATUS[0]} ${PIPESTATUS[1]}; 
0 1 0 

## doesn't work: 
$ a=`false | true`; 
$ echo $? ${PIPESTATUS[0]} ${PIPESTATUS[1]}; 
0 0 

::私はバッククォートを使用していないが、私は出力を保存したいときには動作していないようならば、私は[0] PIPESTATUSを経由して取得することができ、保存最後の変数にはいくつかのプログラムの出力のラインが、プログラムが失敗した場合は伝えることができる:

$ myvar=` ./someprogram | tail -1 `; 
$ if [ "what do i put here" ]; then echo "program failed!"; fi 

理想的には私も答えがあるだけではなく、何が起こっているかを理解したいと思います。

ありがとうございました。

答えて

4

pipefailオプションを設定してください。失敗したパイプラインの最後のコマンドを返します。一つの例:

最初に私はそれを無効にします。コマンドラインで

#!/usr/bin/env perl 

use warnings; 
use strict; 

if (@ARGV) { 
    die "Line1\nLine2\nLine3\n"; 
} 
else { 
    print "Line1\nLine2\nLine3\n"; 
} 

ラン:

myvar=`perl script.pl | tail -1` 
echo $? "$myvar" 

set +o pipefail 

がパイプラインをテストするためにperlスクリプト(script.pl)を作成します。

これは:

0 Line3 

それは正しいようだ、pipefail有効にして見てみましょう:

set -o pipefail 

し、コマンドを実行します。

myvar=`perl script.pl fail 2>&1 | tail -1` 
echo $? "$myvar" 

それ利回り:

255 Line3 
+0

ありがとうございます。私は 'pipefail'について知りませんでした。 – jerry

+0

これはshでも有効です。ありがとうございました。 – AnkurTank

2

私のソリューションを使用していたFIFOと各COMからのメッセージとステータスを取得するためのbash "coproc"組み込み関数パイプのマン。私は前にFIFOを使ったことはなかった。 (オハイオ州の少年、次回はFedoraでBashEclipseを使用しています)。パイプコマンドを管理するための一般的なメカニズムに変わりました。私はこの問題を解決しましたが、10行または20行のコードでは解決しませんでした。 の頑強なドロップイン再利用可能なソリューションの場合は200に似ています(そうするには3日間かかりました)。

私は自分のノートを共有する:

* stderr for all pipe commands goes to the fifos. 
    If you want to get messages from stdout, you must redirect '1>&2', like this: 
    PIPE_ARRAY=("cat ${IMG}.md5" "cut -f1 -d\" \" 1>&2") 
    You must put "2>/fifo" first. Otherwise it won\'t work. example: 
    cat ${IMG}.md5 | cut -f1 -d' ' 1>&2 
    becomes: 
    cat ${IMG}.md5 2>/tmp/fifo_s0 | cut -f1 -d" " 2>/tmp/fifo_s1 1>&2 ; PSA=("${PIPESTATUS[@]}") 

* With more tha one fifo, I found that you must read each fifo in turn. 
    When "fifo1" gets written to, "fifo0" reads are blocked until you read "fifo1" 
    I did\'nt use any special tricks like "sleep", "cat", or extra file descriptors 
    to keep the fifos open. 

* PIPESTATUS[@] must be copied to an array immediately after the pipe command returns. 
    _Any_ reads of PIPESTATUS[@] will erase the contents. Super volatile ! 
    "manage_pipe()" appends '; PSA=("${PIPESTATUS[@]}")' to the pipe command string 
    for this reason. "$?" is the same as the last element of "${PIPESTATUS[@]}", 
    and reading it seems to destroy "${PIPESTATUS[@]}", but it's not absolutly verifed. 

run_pipe_cmd() { 
    declare -a PIPE_ARRAY MSGS 
    PIPE_ARRAY=("dd if=${gDEVICE} bs=512 count=63" "md5sum -b >${gBASENAME}.md5") 
    manage_pipe PIPE_ARRAY[@] "MSGS" # (pass MSGS name, not the array) 
} 
manage_pipe() { 
    # input - $1 pipe cmds array, $2 msg retvar name 
    # output - fifo msg retvar 
    # create fifos, fifo name array, build cnd string from $1 (re-order redirection if needed) 
    # run coprocess 'coproc execute_pipe FIFO[@] "$CMDSTR"' 
    # call 'read_fifos FIFO[@] "M" "S"' (pass names, not arrays for $2 and $3) 
    # calc last_error, call _error, _errorf 
    # set msg retvar values (eval ${2}[${i}]='"${Msg[${i}]}"') 
} 
read_fifos() { 
    # input - $1 fifo array, $2 msg retvar name, $3 status retvar name 
    # output - msg, status retvars 
    # init local fifo_name, pipe_cmd_status, msg arrays 
    # do read loop until all 'quit' msgs are received 
    # set msg, status retvar values (i.e. eval ${3}[${i}]='"${Status[${i}]}"' 
} 
execute_pipe() { 
    # $1 fifo array, $2 cmdstr, $3 msg retvar, $4 status retvar 
    # init local fifo_name, pipe_cmd_status arrays 
    # execute command string, get pipestaus (eval "$_CMDSTR" 1>&2) 
    # set fifo statuses from copy of PIPESTATUS 
    # write 'status', 'quit' msgs to fifo 
} 
0
## PIPESTATUS[0] works to give me the exit status of 'false': 
$ false | true 
$ echo $? ${PIPESTATUS[0]} ${PIPESTATUS[1]} 
0 1 0 

## Populate a $PIPESTATUS2 array: 
$ a=`false | true; printf :%s "${PIPESTATUS[*]}"` 
$ ANS=$?; PIPESTATUS2=(${a##*:}) 
$ [ -n "${a%:*}" ] && a="${a%:*}" && a="${a%$'\n'}" || a="" 
$ echo $ANS ${PIPESTATUS2[0]} ${PIPESTATUS2[1]}; 
0 1 0 

これは$aの終わりにサブシェルの$PIPESTATUS配列を保存し、その後いくつかのシェル変数substring removalを使用して、それを抽出し、私がGet exit codes of a pipe when output is assigned to variable (Command Substitution)に与えた長い例と説明を参照してください。

関連する問題