Вывод команды 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
Ответ 2
Используйте ${PIPESTATUS[0]}
, чтобы получить статус выхода первой команды в трубе.
Подробнее см. http://tldp.org/LDP/abs/html/internalvariables.html#PIPESTATUSREF
См. также http://cfajohnson.com/shell/cus-faq-2.html для других подходов, если ваша оболочка не поддерживает $PIPESTATUS
.
Ответ 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 намного проще.)