Как я могу заставить одну подоболочку bash выйти из основного сценария вызывающей оболочки?

Имея следующий bash-скрипт:

#!/bin/bash

set -e

function foo() {
  # commands that might fails and I want to exit my script
  ...
  echo "result I need as output"
}

my_var=$(foo)

echo "I don't want this if there is an error inside foo"

Использование set -e (в bash 4.4.19), похоже, не работает с подоболочками, т.е. последняя команда echo все еще выполняется). Как я могу написать код для выхода из скрипта, если какая-либо из команд внутри foo завершается с ненулевым кодом выхода.

Я использую bash GNU bash, version 4.4.19(1)-release (x86_64-apple-darwin16.7.0), и результат вызова моего скрипта (где точки заменены недопустимой командой head -this:

$ ./my_script
head: illegal option -- t
usage: head [-n lines | -c bytes] [file ...]
I don't want this if there is an error inside foo

person Gabriel Petrovay    schedule 28.05.2018    source источник
comment
потому что вы не проверили статус выхода head; либо head .. || exit 1, либо включение опции -e внутри подоболочки my_var=$(set -e; foo), первый вариант лучше, потому что ясен и его легче понять другим   -  person Nahuel Fouilleul    schedule 28.05.2018
comment
И если head на самом деле является командой grep ... | head ... | awk ... | xargs ..., как вы можете переписать эти пайпы? Используете (grep ... || exit 1) | (head ... || exit 1) | ...?   -  person Gabriel Petrovay    schedule 28.05.2018
comment
для команды конвейера по умолчанию статус выхода — это статус выхода последней команды конвейера, но его также можно изменить с помощью set -o pipefail, обратите внимание, что pipefail не очищается в подоболочке   -  person Nahuel Fouilleul    schedule 28.05.2018
comment
Спасибо! Если вы добавите эти параметры в ответ с соответствующим комментарием, я думаю, это тоже будет полезно. Это то, что мне действительно было нужно.   -  person Gabriel Petrovay    schedule 28.05.2018


Ответы (1)


Изменено из комментариев

статус выхода команды конвейера — это статус выхода последней команды, его можно изменить с помощью set -o pipefail, так что статус выхода конвейера будет <>0, если статус выхода любой команды равен <>0.

Первый ответ

поскольку вы использовали опцию -e, достаточно, чтобы функция возвращала код выхода, отличный от 0, например return 1

в более общем случае (без set -e) может быть лучше использовать явный выход

my_var=$(foo) || exit 1

может быть достаточно, потому что ошибка может быть записана в стандартную ошибку (унаследованную) подоболочкой.

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

установить -е

Немедленно выйти, если [...] возвращает ненулевой статус. Оболочка не завершается, если команда, которая не удалась, является частью списка команд, следующей за ключевым словом while или until, частью теста в операторе if, частью любой команды, выполняемой в операторах && или || список, за исключением команды, следующей за последними && или ||, [...].

Этот параметр применяется к среде оболочки и к каждой среде подоболочки отдельно (см. Среда выполнения команд) и может привести к выходу из подоболочек до выполнения всех команд в подоболочке.

[...]

И из среды выполнения команд

Подоболочки, созданные для выполнения подстановок команд, наследуют значение параметра -e от родительской оболочки. Если не в режиме POSIX, Bash очищает параметр -e в таких подоболочках.

person Nahuel Fouilleul    schedule 28.05.2018