Как отключить set -e для отдельной команды?

36

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

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

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

Гюстав
источник

Ответы:

29
  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 .

Аркадиуш Драбчик
источник
Благодарность! Я нашел другую возможность: #! / Bin / bash set -e # Раскомментировать следующую строку, чтобы увидеть эффект set -e: #blubb if blubb; затем эхо "Командный блеб был успешным". else echo "Команда blubb завершилась неудачно. Код выхода: $?" фантастический выход нормального сценария
Гюстав
22

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

cmd_to_run || true

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

Эрни
источник
3
faulty_cmd || :это еще одна популярная идиома для этого. (Команда :является синонимом true).
ulidtko
3
@ulidtko - интересно. Провел меня вниз по кроличьей норе, чтобы найти этот stackoverflow.com/questions/3224878/… чтобы получить историю об истинных против:
Эрни
12

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

function xyz {
    return 2
}

xyz && RC=$? || RC=$?
h0tw1r3
источник
8

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

В частности, эта опция игнорируется, если команда является частью теста в операторе 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
Гюстав
источник
2

Другой подход, который я считаю довольно простым (и применим к другим setопциям в дополнение к -e):

Используйте $-для восстановления настроек.

Например:

oldopt=$-
set +e
# now '-e' is definitely disabled.
# do some stuff...

# Restore things back to how they were
set -$oldopt

Хотя, в -eчастности, варианты, которые другие разработали ( || trueили «положили внутрь if»), могут быть более идиоматичными.

JWD
источник
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', проверяет его состояние выхода, а также повторяет и говорит это. Я думаю, это то, что вы просили, или хотя бы что-то подобное? В любом случае, надеюсь, это поможет.

Аддисон Крамп
источник
Чтобы пояснить, я полагаю, что в фигурных скобках, перенаправляемых в / dev / null, есть то, что вам нужно. Это делает команду не имеющей выхода и проверяет ее состояние ошибки, не выходя из программы.
Эддисон Крамп
0

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

bash -c 'set -e ;\
( set +e; bad_command ; echo still here ) ;\
echo even here ; \
bad_command ; \
echo but not here;'
noonex
источник