Как надежно обрабатывать ошибки в функции оболочки, называемой условием? - PullRequest
0 голосов
/ 05 июля 2011

Использование bash 4.1.5:

#!/bin/bash

set -e

foo()
{
        false
        echo "argh, I don't want to get there! What about set -e?!"
}

foo && echo "ok"

Это приводит к следующему выводу:

argh, I don't want to get there! What about set -e?!
ok

Эта проблема возникает всякий раз, когда foo вызывается как условие (то есть внутри if, while, &&, || и т. Д.).foo ведет себя корректно, если вызывается как простая команда.

Я считаю это поведение удивительным и откровенно опасным, поскольку это означает, что поведение функции bash изменяется в зависимости от того, как она вызывается.Например, даже такие простые вещи, как foo и foo && true будут , а не , дадут те же результаты.Это очень беспокоит!Можно только представить, какой хаос это может вызвать, если foo выполняет чувствительные операции ...

Есть ли какой-нибудь обходной путь, который я мог бы использовать, чтобы избежать такой ситуации?

Ответы [ 2 ]

1 голос
/ 05 июля 2011

Поведение, которое вы описываете, ожидаемо и совершенно необходимо.Рассмотрим функцию вроде:

word_is_in_file() {
   grep $1 $2 > /dev/null
}

Теперь рассмотрим скрипт, который использует эту функцию (извините, этот пример немного надуманный, поскольку реальный скрипт, вероятно, просто вызвал бы grep напрямую), чтобы принять решение:

if word_is_in_file $word $file; then
  do_something
else
  do_something_else
fi

Определение функции может быть похоронено в библиотеке функций оболочки, которую автор никогда не видит.Автор не считает сбой grep ошибкой и будет очень озадачен, если из-за него завершится сценарий.

Чтобы получить желаемую семантику, нужно выполнить что-то вроде:

foo() {
   # This function will abort if errors are encountered, but 
   # the script will continue
   sh -e -c '
   false
   echo not reached'
}

foo && echo not reached
echo reached
foo
echo not reached

Семантика set -e также настроена так, чтобы не прерывать сценарий в случае "foo && ..." по той же причине.Это позволяет ветвление.

1 голос
/ 05 июля 2011

Почему бы вам не заставить foo () возвращать ненулевой код выхода, если он не работает?

foo(){
    return 1
    echo "argh, I don't want to get here! What about set -e?!"
}
...