Вывод команды Pipe, но сохраните код ошибки

Как получить правильный код возврата из приложения командной строки unix после того, как я выполнил его через другую команду, которая преуспела?

В деталях, здесь ситуация:

$ tar -cEvhf - -I ${sh_tar_inputlist} | gzip -5 -c > ${sh_tar_file}  --  when only the tar command fails $?=0
$ echo $?
0

И я хотел бы видеть:

$ tar -cEvhf - -I ${sh_tar_inputlist} 2>${sh_tar_error_file} | gzip -5 -c > ${sh_tar_file}
$ echo $?
1

Кто-нибудь знает, как это сделать?

Ответ 1

Вот общее решение, использующее только оболочку POSIX и без временных файлов:

Начиная с трубопровода: foo | бар | Баз

exec 4>&1
error_statuses=`((foo || echo "0:$?" >&3) |
        (bar || echo "1:$?" >&3) | 
        (baz || echo "2:$?" >&3)) 3>&1 >&4`
exec 4>&-

$error_statuses содержит коды состояния любых неудачных процессов, в случайном порядке, с индексами, чтобы указать, какая команда выдала каждое состояние.

# if "bar" failed, output its status:
echo $error_statuses | grep '1:' | cut -d: -f2

# test if all commands succeeded:
test -z "$error_statuses"

# test if the last command succeeded:
echo $error_statuses | grep '2:' >/dev/null

Ответ 3

Посмотрите $PIPESTATUS, который представляет собой переменную массива, содержащую статусы выхода. Таким образом, ${PIPESTATUS[0]} содержит статус выхода первой команды в трубе, ${PIPESTATUS[1]} состояние выхода второй команды и т.д.

Например:

$ tar -cEvhf - -I ${sh_tar_inputlist} | gzip -5 -c > ${sh_tar_file}
$ echo ${PIPESTATUS[0]}

Чтобы распечатать все статусы, используйте:

$ echo ${PIPESTATUS[@]}

Ответ 4

Как отмечали другие, некоторые современные снаряды предоставляют PIPESTATUS для получения этой информации. В классическом sh это немного сложнее, и вам нужно использовать fifo:

#!/bin/sh

trap 'rm -rf $TMPDIR' 0
TMPDIR=$( mktemp -d )
mkfifo ${FIFO=$TMPDIR/fifo}

cmd1 > $FIFO &
cmd2 < $FIFO
wait $!
echo The return value of cmd1 is $?

(Ну, вам не нужно использовать fifo. У вас могут быть команды на раннем этапе в канале, эхо-переменная состояния и eval, что в основной оболочке, перенаправление дескрипторов файлов повсюду и в основном сгибание назад проверьте вещи, но использование fifo намного проще.)