Обработка ошибок кода возврата Bash при использовании ввода heredoc

Мотивация

Я нахожусь в ситуации, когда мне приходится запускать несколько команд bash с одним вызовом bash без возможности написать полный файл сценария (вариант использования: Передача нескольких команд в контейнер в Kubernetes). общее решение состоит в том, чтобы объединить команды с ; или &&, например:

bash -c " \
echo \"Hello World\" ; \
ls -la ; \
run_some_command "

На практике написание таких bash-скриптов чревато ошибками, потому что я часто забываю точку с запятой, что приводит к незаметным ошибкам.

Вдохновленный этим вопросом, я экспериментировал с написанием сценариев в более стандартном стиле, используя heredoc:

bash <<EOF
echo "Hello World"
ls -la
run_some_command
EOF

К сожалению, я заметил разницу в обработке ошибок кода выхода при использовании heredoc. Например:

bash -c " \
run_non_existing_command ; \
echo $? "

выходы (обратите внимание, что $? правильно фиксирует код выхода):

bash: run_non_existing_command: command not found
127

тогда как

bash <<EOF
run_non_existing_command
echo $?
EOF

выходные данные (обратите внимание, что $? не может захватить код выхода по сравнению со стандартным выполнением скрипта):

bash: line 1: run_non_existing_command: command not found
0

Почему версия heredoc ведет себя иначе? Можно ли написать скрипт в стиле heredoc и поддерживать нормальную обработку кода выхода?


person bluenote10    schedule 15.10.2019    source источник
comment
for instance: — ваш экземпляр не объединяет команды (по крайней мере, не так, как я определяю «комбинировать»), он запускает bash -c echo "Hello World", а затем запускает ls -la и run_some_command, все в родительской оболочке. Я думаю, что вам не хватает\слешей   -  person KamilCuk    schedule 15.10.2019
comment
@KamilCuk Правильно исправлено, спасибо! Ошибка копирования и вставки, при развертывании в Kubernetes `` обрабатываются с помощью многострочных строк YAML... Наблюдения должны оставаться действительными.   -  person bluenote10    schedule 15.10.2019
comment
Нет, это не то же самое. Наверное, то же самое было бы bash -c "echo \"Hello World\" ; ls -la ; run_some_command ;"   -  person KamilCuk    schedule 15.10.2019


Ответы (1)


Почему версия heredoc ведет себя иначе?

Потому что $? расширяется перед запуском команды.

Следующее выведет 1, то есть статус выхода команды false:

false
bash <<EOF
run_non_existing_command
echo $?
EOF

В принципе это то же самое, что и следующее, которое напечатает 5:

variable=5
bash <<EOF
variable="This is ignored"
echo $variable
EOF

Можно ли написать скрипт в стиле heredoc и поддерживать нормальную обработку кода выхода?

Если вы хотите, чтобы $? расширялся внутри подоболочки, то:

bash <<EOF
run_non_existing_command
echo \$?
EOF

or

bash <<'EOF'
run_non_existing_command
echo $?
EOF

Также обратите внимание, что:

bash -c \
run_non_existing_command ;
echo $? ;

просто равно:

bash -c run_non_existing_command
echo $?

echo $? не выполняется внутри bash -c.

person KamilCuk    schedule 15.10.2019
comment
Интересно, есть ли простое объяснение, почему цитирование EOF избавляет от необходимости экранировать $?? - person bluenote10; 15.10.2019
comment
Да, так задумано. См. оболочку posix 2.7.4 здесь-документ If any character in word is quoted, .... the here-document lines shall not be expanded. - person KamilCuk; 15.10.2019