Вывод команды трубопровода на тройник, но также сохранение кода выхода команды

У меня есть сценарий оболочки, в который я помещаю команду (mvn clean install) для перенаправления вывода в файл журнала.

#!/bin/bash
...
mvn clean install $@ | tee $logfile
echo $? # Does not show the return code of mvn clean install

Теперь, если mvn clean install завершается с ошибкой, я хочу, чтобы мой сценарий оболочки-оболочки также завершился с этой ошибкой. Но поскольку я отправляю весь вывод в тройник, я не могу получить доступ к коду возврата mvn clean install, поэтому, когда я получаю доступ к $? впоследствии, он всегда 0 (с тех пор, как тройник успешен).

Я попытался разрешить команде записывать вывод ошибки в отдельный файл и потом проверять его, но вывод ошибки mvn всегда пуст (похоже, он записывает только в stdout).

Как я могу сохранить код возврата mvn clean install, но по-прежнему передавать вывод в файл журнала?


person Wolkenarchitekt    schedule 29.07.2011    source источник


Ответы (4)


Поскольку вы используете bash, вместо этого вы можете использовать его переменную $ PIPESTATUS из $?:

mvn clean install $@ | tee $logfile
echo ${PIPESTATUS[0]}
person Frédéric Hamidi    schedule 29.07.2011
comment
Как упоминалось ниже, если у вас более одного канала, вам необходимо проверить статус каждой команды, чтобы узнать, где она не удалась. - person Joshua Olson; 23.08.2013
comment
Отлично работает, спасибо. - person plang; 14.10.2013
comment
Также очень важно: переменная недолговечна, поэтому даже при ее повторении вы потеряете значение при запуске конвейера. Назначьте его другой переменной, если только вы не получите к нему доступ сразу и только один раз. - person Davor Cubranic; 12.09.2020

Вы можете установить pipefail параметр оболочки на чтобы добиться желаемого поведения.

Из Справочного руководства по Bash:

Статус выхода конвейера - это статус выхода последней команды в конвейере, если не включена опция pipefail (см. The Set-Builtin). Если pipefail включен, статус возврата конвейера - это значение последней (самой правой) команды для выхода с ненулевым статусом или ноль, если все команды завершаются успешно.

Пример:

$ false | tee /dev/null ; echo $?
0
$ set -o pipefail
$ false | tee /dev/null ; echo $?
1

Чтобы восстановить исходную настройку трубы:

$ set +o pipefail
person Jukka Matilainen    schedule 29.07.2011
comment
Это кажется более элегантным решением, чем принятое решение. - person Stefaan; 20.11.2012
comment
Согласованный. Принятый ответ требует, чтобы вы знали заранее, какая команда в ваших каналах завершится ошибкой. Если вы объединяете вместе 5 разных команд, вам нужно будет угадать, какая из них в массиве не сработает. - person noahlz; 01.06.2013
comment
Или сделайте петлю над PIPESTATUS - person Joshua Olson; 23.08.2013
comment
для восстановления исходной настройки трубы: $ set +o pipefail - person eddie; 27.09.2016
comment
Обратите внимание, pipefail также поддерживается dash в ubuntu - person lightswitch05; 07.06.2017
comment
Отличный ответ, однако я хотел бы указать, что set +o pipfail отключит pipefail (не вернет его в исходное состояние), как говорится в документации Using ‘+’ rather than ‘-’ causes these options to be turned **off**. The options can also be used upon invocation of the shell. The current set of options may be found in $-. - person jave.web; 23.09.2019
comment
Также, если вы собираетесь использовать однострочник: bash -c "set -o pipefail && false | tee log.txt" выйдет с кодом ошибки. Очень полезно для чего-то вроде процесса сборки, который вы регистрируете. - person Robert; 09.06.2020

Вы можете запустить команду mvn и кэшировать код выхода ... В своем примере я использую команду "false".

$ { false ; echo $? > /tmp/false.status ; } | tee $logfile
$ cat /tmp/false.status
1

Таким образом, вы можете использовать содержимое файла состояния для принятия дальнейших решений.

Мне теперь любопытно, есть ли более красноречивый способ добиться этого.

person Demosthenex    schedule 29.07.2011
comment
Я надеюсь, что окончательный ответ не зависит от оболочки (например, только для bash). - person Demosthenex; 29.07.2011
comment
Идеально! Я предпочитаю, чтобы этот не полагался только на bash :-) Спасибо @Demosthenex - person Ciges; 18.10.2018
comment
Но я использовал () вместо {} для захвата вывода .... - person Ciges; 18.10.2018

Обходной путь (примечание: решение perfer @ Frederic):

f=`mktemp`
(mvn clean install $@; echo $?>$f) | tee $logfile
e=`cat $f` #error in variable e
rm $f
person Karoly Horvath    schedule 29.07.2011
comment
Можно ли сохранить вилку с read e < $f вместо cat? - person Jens; 14.08.2012
comment
Конечно. и вы, вероятно, захотите создать временный файл, чтобы избежать состояний гонки. но, как видите, есть решения и получше ... - person Karoly Horvath; 14.08.2012