27

Команда set -e сразу приводит к сбою скрипта bash, когда любая команда возвращает ненулевой код завершения.

  1. Есть ли простой и элегантный способ отключить это поведение для отдельной команды в скрипте?

  2. В каких местах эта функциональность описана в Справочном руководстве Bash (http://www.gnu.org/software/bash/manual/bashref.html)?

6 ответов6

28
  1. Что-то вроде этого:

    #!/usr/bin/env bash
    
    set -e
    echo hi
    
    # disable exitting on error temporarily
    set +e
    aoeuidhtn
    echo next line
    
    # bring it back
    set -e
    ao
    
    echo next line
    

    Бежать:

    $ ./test.sh
    hi
    ./test.sh: line 7: aoeuidhtn: command not found
    next line
    ./test.sh: line 11: ao: command not found
    
  2. Это описано в set встроенной помощи:

    $ type set
    set is a shell builtin
    $ help set
    (...)
    Using + rather than - causes these flags to be turned off.
    

То же самое описано здесь: https://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin.

18

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

cmd_to_run || true

Это вернет 0 (true), поэтому не следует запускать set -e

6

Если опция "немедленно покинуть оболочку" применяется или игнорируется, зависит от контекста выполняемой команды (см. Раздел "Справочное руководство по Bash" в Set Builtin - благодаря Arkadiusz Drabczyk).

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

#!/bin/bash

set -e

# Uncomment next line to see set -e effect:
#blubb

if blubb; then
  echo "Command blubb was succesful."
else 
  echo "Command blubb failed. Exit code: $?"
fi
echo "Script exited normally."

Можно опустить оператор "then" и использовать меньше строк:

if blubb; then :;
else echo "Command blubb failed. Exit code: $?"; fi
4

Если вы пытаетесь перехватить код возврата / ошибки (функция или ответвление), это работает:

function xyz {
    return 2
}

xyz && RC=$? || RC=$?
0

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

#!/bin/sh

args=""
for argcol in $*
do
    args="${args} ${argcol}"
done
fortunevar=""
fortfail=""
{
    set +e
    fortunevar=`fortune $args`
    fortfail=$?
    set -e
} &> /dev/null
if [ $fortfail == 0 ]
then
    echo ${fortunevar}
    say ${fortunevar}
else
    echo misfortune: an illegal option was detected!
    echo misfortune: usage: misfortune [-afilosw] [-m pattern][ [#%] file/directory/all]
fi

Это захватывает вывод 'fortune', проверяет его состояние выхода, а также повторяет и говорит это. Я думаю, это то, что вы просили, или хотя бы что-то подобное? В любом случае, надеюсь, это поможет.

0

Я люблю запускать subshell, если хочу временно что-то изменить. Команда ниже демонстрирует, что первая команда bad_command игнорируется, а вторая прерывает выполнение.

bash -c 'set -e ;\
( set +e; bad_command ; echo still here ) ;\
echo even here ; \
bad_command ; \
echo but not here;'

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