2016-12-27 3 views
4

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

set -o errexit 
set -o nounset 
set -o pipefail 

Эти варианты, однако, не работает, как ожидалось для функций Bash, который поступает через ||.

E.g. в сценарии

#!/bin/bash 

set -o errexit 
set -o nounset 
set -o pipefail 

my_function() { 
    test -z "$1" 
    echo "this SHOULD NOT be printed" 
} 

my_function 1 || echo "???" # 1 

my_function 1 # 2 

echo "this will not be printed" 

Line # 2 заставит скрипт завершается с кодом 1 без какого-либо выхода. Это то, чего я ожидаю.

Линия # 1 смущает меня на самом деле: my_function будет успешно завершена, печать «этого НЕ ДОЛЖНА быть напечатана» и возврата кода 0, таким образом, «???» не будет напечатано.

Как я могу сделать Bash для обработки my_function на линии # 1 такой же неудачный быстрый способ, как на линии # 2?

+0

Просто из любопытства, где вы видели эти рекомендации? –

ответ

2

Глядя на руководство Баш, вот что говорит по trap команды:

trap [-lp] [arg] [sigspec …]

Если sigspec является ERR, команда-аргумент выполняется всякий раз, когда трубопровод (который может состоять из одна простая команда), список или команда возвращает ненулевой статус выхода с учетом следующих условий: . Ловушка ERR не выполняется, если неудавшаяся команда является частью списка команд сразу после ключевого слова while или while, часть теста, следующего за зарезервированными словами if или elif, частью команды , выполненной в или & или | | кроме команды, следующей за final & & или ||, любая команда в конвейере, но последняя, ​​или если статус возврата инвертируется с использованием!. Это те же самые условия, соблюдаемые параметром errexit (-e).

Посмотрите на последнее предложение особенно. Что объясняет его!

6

Существуют также лучшие рекомендации not to use set -e/errexit:

Очевидно, что мы не хотим, чтобы прервать, когда условная (в if [ -d /foo ]; then), возвращает ненулевое значение. [...] Разработчики решили сделать кучу специальных правил, таких как «команды, которые являются частью теста if, являются иммунными», или «команды в конвейере, отличные от последнего, невосприимчивы».

Эти правила чрезвычайно запутаны, и они по-прежнему не могут поймать даже некоторые необычайно простые случаи. Хуже того, правила меняются с одной версии Bash на другую, так как Bash пытается отслеживать чрезвычайно скользкое определение POSIX этой «функции». Когда задействован SubShell, все еще хуже - поведение изменяется в зависимости от того, вызывается ли Bash в режиме POSIX.

Если сценарий был остановиться на ненулевым возвращения, foo || bar также будет бесполезно, потому что bar никогда не будет работать (сценарий будет вместо выхода).Поэтому одно из этих свернутых правил состоит в том, что ненулевые возвраты в командах с левой стороны от && или || не приведут к тому, что скрипт завершит работу. Это эффект, который вы видите.

Невозможно сделать set -e правильно и нет автоматической замены. Вы не можете заставить его работать так, как вы хотите, не прибегая к ручной обработке ошибок.

Смежные вопросы