Есть ли что-то похожее на pipefail для нескольких команд, например оператор try, но внутри bash. Я хотел бы сделать что-то вроде этого:
echo "trying stuff"
try {
command1
command2
command3
}
И в любой момент, если какая-либо команда завершится неудачно, пропустите и отобразите ошибку этой команды. Я не хочу делать что-то вроде:
command1
if [ $? -ne 0 ]; then
echo "command1 borked it"
fi
command2
if [ $? -ne 0 ]; then
echo "command2 borked it"
fi
И так далее ... или что-то вроде:
pipefail -o
command1 "arg1" "arg2" | command2 "arg1" "arg2" | command3
Потому что аргументы каждой команды, которой я верю (поправьте меня, если я ошибаюсь), будут мешать друг другу. Эти два метода кажутся мне ужасно скучными и неприятными, поэтому я обращаюсь к более эффективному методу.
set -euo pipefail
.set -e
это ужасная идея. См. Упражнения в BashFAQ # 105, где обсуждаются лишь некоторые из неожиданных крайних случаев, которые он вводит, и / или сравнение, показывающее несовместимость между реализациями различных оболочек (и версий оболочки), в in-ulm.de/~mascheck/various/set -е .Ответы:
Вы можете написать функцию, которая запускает и тестирует команду для вас. Предположим,
command1
иcommand2
переменные среды, которые были установлены для команды.источник
$*
, он потерпит неудачу, если в аргументах есть пробелы; используйте"$@"
вместо этого. Точно так же поместите$1
в кавычки вecho
команде.test
поскольку это встроенная команда.ls
. Если вы вызываетеls foo
и получаете сообщение об ошибке формы,ls: foo: No such file or directory\n
вы понимаете проблему. Если вместо этого вы получаете,ls: foo: No such file or directory\nerror with ls\n
вы отвлекаетесь от лишней информации. В этом случае достаточно легко утверждать, что избыточность тривиальна, но она быстро растет. Краткие сообщения об ошибках важны. Но что еще более важно, этот тип оболочки поощряет слишком писателей полностью опускать хорошие сообщения об ошибках.Что вы подразумеваете под "выкинуть и повторить ошибку"? Если вы имеете в виду, что хотите, чтобы скрипт завершился, как только какая-либо команда не сработала, просто сделайте
в начале сценария (но обратите внимание на предупреждение ниже). Не пытайтесь повторить сообщение об ошибке: пусть ошибочная команда справится с этим. Другими словами, если вы делаете:
и команда2 завершается неудачно, при выводе сообщения об ошибке в stderr, кажется, что вы достигли того, чего хотите. (Если я не понимаю, что вы хотите!)
Как следствие, любая команда, которую вы пишете, должна вести себя хорошо: она должна сообщать об ошибках в stderr вместо stdout (пример кода в вопросе печатает ошибки в stdout) и должна завершать работу с ненулевым состоянием в случае неудачи.
Однако я больше не считаю это хорошей практикой.
set -e
изменил свою семантику с разными версиями bash, и хотя он отлично работает для простого скрипта, существует так много крайних случаев, что он по сути непригоден для использования. (Рассмотрим такие вещи, как:set -e; foo() { false; echo should not print; } ; foo && echo ok
семантика здесь несколько разумна, но если вы преобразуете код в функцию, которая полагается на настройку параметра для преждевременного завершения, вы можете легко получить укус.) IMO лучше написать:или
источник
trap some_func 0
, выполнитsome_func
на выходе)|| exit
явно после каждой команды.У меня есть набор функций сценариев, которые я широко использую в своей системе Red Hat. Они используют системные функции
/etc/init.d/functions
для печати зеленого[ OK ]
и красного[FAILED]
индикаторов состояния.При желании вы можете задать для
$LOG_STEPS
переменной имя файла журнала, если вы хотите регистрировать, какие команды не выполняются.использование
Вывод
Код
источник
Для краткости написания кода для проверки успешности каждой команды:
Это все еще утомительно, но по крайней мере это читается.
источник
command1 &> /dev/null || echo "command1 borked it"
command1 || (echo command1 borked it ; exit)
Альтернатива состоит в том, чтобы просто объединить команды вместе с
&&
тем, чтобы первая, которая потерпит неудачу, препятствовала выполнению остальных:Это не тот синтаксис, который вы задали в вопросе, но это общий шаблон описанного вами варианта использования. В общем, команды должны отвечать за сбои печати, чтобы вам не приходилось делать это вручную (возможно, с
-q
флажком, чтобы глушить ошибки, когда они вам не нужны). Если у вас есть возможность изменить эти команды, я бы отредактировал их так, чтобы они выкрикивали при неудаче, а не заключал их в что-то еще, что делает это.Обратите внимание, что вам не нужно делать:
Вы можете просто сказать:
И когда вы делаете необходимость проверки кодов возврата использовать арифметическую контекст вместо
[ ... -ne
:источник
Вместо того, чтобы создавать функции бегуна или использовать
set -e
, используйтеtrap
:Ловушка даже имеет доступ к номеру строки и командной строке команды, которая ее сработала. Переменные
$BASH_LINENO
и$BASH_COMMAND
.источник
trap - ERR
чтобы выключить ловушку в конце «блока».Лично я предпочитаю использовать легкий подход, как показано здесь ;
Пример использования:
источник
источник
$*
, он потерпит неудачу, если в аргументах есть пробелы; используйте"$@"
вместо этого. (Хотя $ * вecho
команде хорошо .)Я разработал почти безупречную реализацию try & catch в bash, которая позволяет вам писать такой код:
Вы можете даже вложить блоки try-catch внутри себя!
Код является частью моего bash шаблон / рамки . Это дополнительно расширяет идею try & catch с такими вещами, как обработка ошибок с обратным следом и исключениями (плюс некоторые другие приятные функции).
Вот код, который отвечает только за try & catch:
Не стесняйтесь использовать, раскошелиться и внести свой вклад - это на GitHub .
источник
Извините, что я не могу прокомментировать первый ответ, но вы должны использовать новый экземпляр для выполнения команды: cmd_output = $ ($ @)
источник
Для пользователей раковин рыбы, которые натыкаются на эту тему.
Позвольте
foo
быть функцией, которая не "возвращает" (эхо) значение, но она устанавливает код выхода, как обычно.Чтобы избежать проверки
$status
после вызова функции, вы можете сделать:И если это слишком долго, чтобы поместиться в одну строку:
источник
Когда я использую,
ssh
мне нужно различать проблемы, вызванные проблемами соединения и кодами ошибок удаленной команды в режимеerrexit
(set -e
). Я использую следующую функцию:источник
Вы можете использовать удивительное решение @ john-kugelman, найденное выше для систем, не относящихся к RedHat, закомментировав эту строку в своем коде:
Затем вставьте приведенный ниже код в конце. Полное раскрытие: это просто прямое копирование и вставка соответствующих битов вышеупомянутого файла, взятых из Centos 7.
Протестировано на MacOS и Ubuntu 18.04.
источник
Проверка статуса в функциональном порядке
Использование:
Вывод
источник