Согласно этому справочному руководству :
-E (также -o errtrace)
Если установлено, любая ловушка в ERR наследуется функциями оболочки, подстановками команд и командами, выполняемыми в среде подоболочки. Ловушка ERR обычно не наследуется в таких случаях.
Тем не менее, я должен интерпретировать это неправильно, потому что следующее не работает:
#!/usr/bin/env bash
# -*- bash -*-
set -e -o pipefail -o errtrace -o functrace
function boom {
echo "err status: $?"
exit $?
}
trap boom ERR
echo $( made up name )
echo " ! should not be reached ! "
Я уже знаю простое назначение, my_var=$(made_up_name)
выйдет из скрипта с set -e
(т.е. errexit).
Является ли -E/-o errtrace
должен работать как приведенный выше код? Или, скорее всего, я неправильно понял?
bash
command-substitution
dgo.a
источник
источник
echo $( made up name )
на$( made up name )
производит желаемое поведение. У меня нет объяснения, хотя.var=$( pipe )
и$( pipe )
примеры будут представлять конечные точки канала, аpipe > echo
не будут. Моя страница руководства гласит: «1. Сбой какой-либо отдельной команды в многокомпонентном конвейере не должен приводить к выходу оболочки. Должен рассматриваться только сбой самого конвейера».echo
всегда возвращает 0. Это должно учитываться при анализе ...Ответы:
Примечание:
zsh
будет жаловаться на «плохие шаблоны», если вы не настроите его для принятия «встроенных комментариев» для большинства примеров здесь и не будете запускать их через прокси-оболочку, как я это сделалsh <<-\CMD
.Итак, как я уже говорил в комментариях выше, я не знаю конкретно о bash
set -E
, но я знаю, что POSIX-совместимые оболочки предоставляют простой способ проверки значения, если вы этого хотите:Вы увидите , что , хотя я использовал ,
parameter expansion
чтобы проверить${empty?} _test()
ещеreturn
S проход - как в проявили последнееecho
Это происходит потому , что не удалось значение убивает$( command substitution )
подоболочку , который содержит его, но его родительские оболочки -_test
в это время - продолжает грузоперевозку. Иecho
не важно - это много счастлив служить только\newline; echo
это не тест.Но учтите это:
Поскольку я теперь вводил
_test()'s
вход с предварительно оцененным параметром, функцияINIT here-document
теперь_test()
даже не пытается запускаться. Более того,sh
оболочка, по-видимому, полностью отдает призрак иecho "this doesnt even print"
даже не печатает.Вероятно, это не то, что вы хотите.
Это происходит потому, что
${var?}
расширение параметра style предназначено для выходаshell
в случае отсутствия параметра, оно работает следующим образом :Я не буду копировать / вставлять весь документ, но если вы хотите потерять
set but null
значение, используйте форму:С,
:colon
как указано выше. Если вы хотите, чтобыnull
значение было успешным, просто опустите двоеточие. Вы также можете отрицать это и потерпеть неудачу только для заданных значений, как я покажу позже.Еще один прогон
_test():
Это работает со всеми видами быстрых тестов, но выше вы увидите, что
_test()
запуск из серединыpipeline
сбоев, и фактически его содержащаяcommand list
подоболочка сбоит полностью, так как ни одна из команд в функции не выполняется, ни следующийecho
запуск вообще, хотя также показано, что это может быть легко проверено, потому чтоecho "now it prints"
теперь печатает.Полагаю, дьявол кроется в деталях. В приведенном выше случае оболочка, которая выходит, не является сценарием,
_main | logic | pipeline
а( subshell in which we ${test?} ) ||
требует небольшой песочницы.И это может быть неочевидно, но если вы хотите передать только противоположный случай или только
set=
значения, это тоже довольно просто:Приведенный выше пример использует все 4 формы POSIX параметра замещения и их различный
:colon null
илиnot null
испытание. Больше информации в ссылке выше, и вот она снова .И я думаю, что мы должны показать нашу
_test
работу функции, верно? Мы просто объявляемempty=something
в качестве параметра нашей функции (или в любое время заранее):Следует отметить, что эта оценка стоит отдельно - она не требует дополнительного теста, чтобы провалиться. Еще пара примеров:
И вот, наконец, мы возвращаемся к первоначальному вопросу: как обрабатывать ошибки в
$(command substitution)
подоболочке? Правда в том, что есть два пути, но ни один не прямой. Суть проблемы - процесс оценки оболочки - расширения оболочки (включая$(command substitution)
) происходят раньше в процессе оценки оболочки, чем текущее выполнение команды оболочки - когда ваши ошибки могут быть перехвачены и захвачены.Проблема заключается в том, что к тому времени, когда текущая оболочка оценивает ошибки,
$(command substitution)
подоболочка уже была заменена - ошибок не осталось.Так каковы два пути? Либо вы делаете это явно в рамках
$(command substitution)
подоболочке с помощью тестов, как без тестов, либо поглощаете ее результаты в текущей переменной оболочки и проверяете ее значение.Способ 1:
Способ 2:
Это не удастся, независимо от количества переменных, объявленных в строке:
И наше возвращаемое значение остается постоянным:
ТЕПЕРЬ ЛОВУШКА:
источник
echo "abc" "${v1:?}"
оно не выполняется (abc никогда не печатался). И оболочка возвращает 1. Это верно даже при наличии команды или без"${v1:?}"
нее ( непосредственно на клиенте). Но для сценария OP все, что требовалось для запуска ловушки, - это размещение присваивания его переменной, содержащей замену несуществующей команды в одной строке. В противном случае поведение echo должно возвращать 0 всегда, если оно не прерывается, как в описанных вами тестах.v=$( madeup )
. Я не вижу, что с этим небезопасно. Это просто задание, например, человек неправильно ввел командуv="$(lss)"
. Это ошибки. Да, вы можете проверить состояние ошибки последней команды $? - потому что это команда в строке (присвоение без имени команды) и ничего больше - не аргумент для echo. Кроме того, здесь она фиксируется функцией как! = 0, поэтому вы получаете обратную связь дважды. Иначе, конечно, как вы объясняете, есть лучший способ сделать это упорядоченно в рамках, но у OP была одна строка: эхо плюс его неудачная замена. Он задавался вопросом об эхо.В вашем скрипте это выполнение команды (
echo $( made up name )
). В bash команды разделяются либо ; или с новой строкой . В команде$( made up name )
считается частью команды. Даже если эта часть завершится неудачно и вернется с ошибкой, вся команда будет выполнена успешно, так какecho
не знаю об этом. По мере возврата команды с 0 ловушка не срабатывает.Вы должны поместить это в две команды, назначение и эхо
источник
echo $var
не терпит неудачу -$var
расширяется, чтобы опустеть, прежде чем когда-либоecho
фактически смотрит на это.Это связано с ошибкой в bash. На этапе подстановки команды в
made
выполняется (или не может быть найден) в подоболочке, но подоболочка «оптимизирована» таким образом, что она не использует некоторые ловушки из родительской оболочки. Это было исправлено в версии 4.4.5 :С bash 4.4.5 или выше вы должны увидеть следующий вывод:
Обработчик ловушек был вызван, как и ожидалось, затем подоболочка завершается. (
set -e
только вызывает выход подоболочки, а не родительский элемент, так что сообщение «не должно быть достигнуто» должно быть фактически достигнуто.)Обходной путь для старых версий заключается в принудительном создании полной неоптимизированной подоболочки:
Лишние пробелы необходимы для отличия от Арифметического Расширения.
источник