Ответ 1
Возможно, вы могли бы вывести значение выхода из PIPESTATUS в $?
command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )
Чтобы перенаправить (и добавить) stdout и stderr в файл, а также отобразить его на терминале, я делаю это:
command 2>&1 | tee -a file.txt
Однако есть ли другой способ сделать это, чтобы получить точное значение для статуса выхода?
То есть, если я тестирую $?
, я хочу видеть статус выхода command
, а не статус выхода tee
.
Я знаю, что я могу использовать ${PIPESTATUS[0]}
здесь вместо $?
, но я ищу другое решение, которое не требует проверки PIPESTATUS
.
Возможно, вы могли бы вывести значение выхода из PIPESTATUS в $?
command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )
Другая возможность, с некоторыми bash
вариантами, состоит в том, чтобы включить параметр pipefail
:
pipefail
Если установлено, возвращаемое значение конвейера значение последнего (самого правого) для выхода с ненулевым статус или ноль, если все команды в конвейер успешно завершен. Эта опция по умолчанию отключена.
set -o pipefail
...
command 2>&1 | tee -a file.txt || echo "Command (or tee?) failed with status $?"
Это, как было сказано, единственный способ обеспечения функциональности PIPESTATUS
портативно (например, так, что он также работал с POSIX sh
) немного свернут, т.е. требуется, чтобы временный файл распространял статус выхода из канала назад к процессу родительской оболочки:
{ command 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a file.txt
if [ "`cat \"/tmp/~pipestatus.$$\"`" -ne 0 ] ; then
...
fi
или, инкапсулируя для повторного использования:
log2file() {
LOGFILE="$1" ; shift
{ "[email protected]" 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a "$LOGFILE"
MYPIPESTATUS="`cat \"/tmp/~pipestatus.$$\"`"
rm -f "/tmp/~pipestatus.$$"
return $MYPIPESTATUS
}
log2file file.txt command param1 "param 2" || echo "Command failed with status $?"
или, более общий, возможно:
save_pipe_status() {
STATUS_ID="$1" ; shift
"[email protected]"
echo $? >"/tmp/~pipestatus.$$.$STATUS_ID"
}
get_pipe_status() {
STATUS_ID="$1" ; shift
return `cat "/tmp/~pipestatus.$$.$STATUS_ID"`
}
save_pipe_status my_command_id ./command param1 "param 2" | tee -a file.txt
get_pipe_status my_command_id || echo "Command failed with status $?"
...
rm -f "/tmp/~pipestatus.$$."* # do this in a trap handler, too, to be really clean
Использовать замену процесса:
command > >( tee -a "$logfile" ) 2>&1
tee работает в подоболочке, поэтому $? содержит статус выхода команды.
Существует тайный способ POSIX:
exec 4>&1; R=$({ { command1; echo $? >&3 ; } | { command2 >&4; } } 3>&1); exec 4>&-
Он установит переменную R
в возвращаемое значение command1
, а вывод на выходе от command1
до command2
, выход которого перенаправляется на выход родительской оболочки.