56

Рассмотрим следующий код

outer-scope.sh

#!/bin/bash
set -e
source inner-scope.sh
echo $(inner)
echo "I thought I would've died :("

inner-scope.sh

#!/bin/bash
function inner() { echo "winner"; return 1; }

Я пытаюсь получить outer-scope.sh для выхода при сбое вызова inner() . Так как $() вызывает вложенную оболочку, этого не происходит.

Как еще получить выходные данные функции, сохранив тот факт, что функция может завершиться с ненулевым кодом выхода?

3 ответа3

86

$() сохраняет статус выхода; Вы просто должны использовать его в утверждении, которое не имеет собственного статуса, например, в присваивании.

output=$(inner)

После этого $? будет содержать статус выхода inner , и вы можете использовать для этого все виды проверок:

output=$(inner) || exit $?
echo $output

Или же:

if ! output=$(inner); then
    exit $?
fi
echo $output

Или же:

if output=$(inner); then
    echo $output
else
    exit $?
fi

(Примечание: пустой exit без аргументов эквивалентен exit $? - то есть он завершается со статусом выхода последней команды. Я использовал вторую форму только для ясности.)


Кроме того, для записи: source полностью не связан в этом случае. Вы можете просто определить inner() в файле outer-scope.sh с теми же результатами.

23

Смотрите BashFAQ/002:

Если вы хотите оба (выходной и выходной статус):

output=$(command)
status=$? 

Особый случай

Обратите внимание на сложный случай с локальными переменными функции, сравните следующий код:

f() { local    v=$(echo data; false); echo output:$v, status:$?; }
g() { local v; v=$(echo data; false); echo output:$v, status:$?; }

Мы получим:

$ f     # fooled by 'local' with inline initialization
output:data, status:0

$ g     # a good one
output:data, status:1

Зачем?

Когда выходные данные подоболочки используются для инициализации local переменной, статус выхода больше не подчиненной оболочки, а local команды, которая, скорее всего, будет 0 .

Смотрите также https://stackoverflow.com/a/4421282/537554

4
#!/bin/bash
set -e
source inner-scope.sh
foo=$(inner)
echo $foo
echo "I thought I would've died :("

При добавлении echo подоболочка не стоит отдельно (не проверяется отдельно) и не прерывается. Назначение обходит эту проблему.

Вы также можете сделать это и перенаправить вывод в файл для последующей обработки.

tmpfile=$( mktemp )
inner > $tmpfile
cat $tmpfile
rm $tmpfile

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .