удар: перенаправление (и добавляют) stdout и stderr в файл и терминал и получают надлежащий статус выхода

Чтобы перенаправить (и добавить) stdout и stderr в файл, также отображая его на терминале, я делаю это:

command 2>&1 | tee -a file.txt

Однако там другой путь состоит в том, чтобы сделать это таким образом, что я получаю точное значение для статуса выхода?

Таким образом, если я тестирую $?, Я хочу видеть статус выхода command, не статус выхода tee.

Я знаю, что могу использовать ${PIPESTATUS[0]} здесь вместо $?, но я ищу другое решение, которое не включило бы необходимость проверить PIPESTATUS.

35
задан TRiG 31 July 2015 в 16:18
поделиться

3 ответа

Возможно, вы могли бы поместить значение выхода из PIPESTATUS в $?

command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )
30
ответ дан 27 November 2019 в 15:38
поделиться

Существует загадочный способ сделать это в POSIX:

exec 4>&1; R=$({ { command1; echo $? >&3 ; } | { command2 >&4; } } 3>&1); exec 4>&-

Он установит для переменной R возвращаемое значение ] command1 , и вывод команды command1 на command2 , вывод которой перенаправляется на вывод родительской оболочки.

3
ответ дан 27 November 2019 в 15:38
поделиться

Другая возможность, с некоторыми вариантами 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
  { "$@" 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
  "$@"
  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
6
ответ дан 27 November 2019 в 15:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: