Как определить функцию оболочки штампа?

Примечание: это не дубликат Есть ли в bash эквивалент die error msg , как показано в конце этого поста.

Рассмотрим функцию оболочки

foo () {
    echo "testing..." 1>&2
    return 1
    echo "should never reach this point" 1>&2
}

Ниже показано ожидаемое поведение foo:

% foo || echo $?
testing...
1

Я хотел бы инкапсулировать функциональность, показанную в первых двух строках foo, в функцию die, чтобы определение foo можно было сократить до

foo () {
    die 1 "testing..."
    echo "should never reach this point" 1>&2
}

... при этом сохраняя свое первоначальное поведение.

Меня интересует в первую очередь zsh, но мне также будут интересны ответы, подходящие для сценариев bash и/или /bin/sh, если они различаются.


Кстати, это не сработает:

die () {
    local exit_code=$1
    shift
    echo "$*" 1>&2
    exit $exit_code
}

Если запустить из командной строки версию foo, которая использует этот die, результатом будет уничтожение текущего шелла (по крайней мере, это результат, который я получаю, когда пытаюсь сделать что-то подобное). Вот почему этот вопрос не является дубликатом Есть ли в bash эквивалент сообщения об ошибке. Во всяком случае, ответ на этот другой вопрос не удовлетворит здесь моих требований.


person kjo    schedule 02.04.2013    source источник


Ответы (2)


Строго говоря, я не думаю, что то, что вы хотите, возможно. Вы не можете вернуться из функции, просто вызвав другую функцию. Это может быть близко к тому, что вы хотите, хотя:

die () {
    echo "${*:2}" 1>&2
    return $1
}

foo () (      # Parentheses, not braces, to enclose the body
    set -e
    die 1 "testing..."
    echo "Shouldn't reach here" 1>&2
)

Когда die возвращается со статусом 1, set -e вызывает выход из текущей оболочки. Однако тело foo запустило новую подоболочку, поэтому она завершается, возвращая управление оболочке, вызвавшей foo. Однако есть две вопиющие проблемы:

  1. set -e; die... не короче echo...; return 1
  2. Если сделать тело foo подоболочкой, любые переменные, заданные в этой функции, не будут видны вызывающей стороне.
person chepner    schedule 04.04.2013
comment
Первая проблема, которую вы упомянули, — это всего лишь артефакт игрушечного примера; в реальной функции обычно есть несколько вызовов die, для которых достаточно одного set -e. Вторая проблема гораздо серьезнее, так как одним из основных преимуществ использования функции, а не сценария оболочки, как раз и является тот факт, что функции могут изменять текущую среду оболочки. - person kjo; 05.04.2013

Начиная с zsh 4.3.4, вы можете использовать синтаксис throw/catch. Я нахожу это гораздо менее проблематичным, чем «set -e» старой школы или выход для обработки ошибок. Просто убедитесь, что вы делаете «autoload -U throw catch», чтобы получить к ним доступ. Подробности смотрите в "man zshcontrib".

person Steve Goranson    schedule 01.12.2013