2015-10-13 2 views
3

Я пытаюсь сделать функцию, которая может прервать выполнение скрипта (из-за фатальную ошибку): примерПрервать Баш скрипт с помощью функции

quit() { 
    echo -e "[ERROR]" | log 
    exit 1 
} 

Вызова:

if [ "$#" -eq 1 ]; then 
    # Do stuff 
else 
    echo -e "function getValue: wrong parameters" | log 
    quit 
fi 

Функция quit называется (echo в файле журнала), но скрипт продолжает работать. Я прочитал, что exit только завершает подоболочку (это правда?), Что означает, что она завершает функцию quit, но не весь скрипт.

На данный момент я предпочитаю не использовать код возврата в методе quit, поскольку он подразумевает много рефакторинга кода.

Есть ли способ остановить сценарий от функции quit?

EDIT: полный пример случая, когда появляется ошибка:

#!/bin/bash 

logfile="./testQuit_log" 

quit() { 
    echo "quit" | log 
    exit 1 
} 

log() { 
    read data 
    echo -e "$data" | tee -a "$logfile" 
} 


foo() { 
    if [ "$#" -ne 1 ]; then 
    echo "foo error" | log 
    quit 
    fi 
    echo "res" 
} 

rm $logfile 

var=`foo p1 p2` 
var2=`foo p1` 

echo "never echo that!" | log 

EDIT2: он работает правильно, когда я включаю эти строки:

var=`foo p1 p2` 
var2=`foo p1` 

с

var= foo p1 p2 
var2= foo p1 

Любые объяснения? Это из-за подоболочки?

+3

'exit' будет выйти из сценария. Функция не является скриптом. Это должно работать так, как написано. Можете ли вы написать короткий, но полный образец, который не работает так, как вы видите? –

+1

Почему вы кладете '-e' на все эхо? Он не переносится и ничего не делает в обоих случаях, которые вы показываете. ('printf' будет интерпретировать C escape-последовательностей в своей строке формата и переноситься. Просто помните, что в отличие от echo он автоматически не добавляет' \ n', поэтому вам нужно добавить это в формат, если вы этого хотите.) – rici

+0

Вопрос отредактирован. Я думаю, что нашел решение, но я не совсем уверен, что понимаю, что там происходит ... – DavidL

ответ

4

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

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

foo() { 
    if [ "$#" -ne 1 ]; then 
     echo "foo error" | log 
     return 1 
    else 
     echo "res" 
     # return 0 is the default 
    fi 
} 

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

var=$(foo p1 p2) || exit 1 
var2=$(foo p1) || exit 1 

Просто чтобы быть ясно, то || ветвь не вводится, если задание не удается (не будет), но если в командной строке внутри подстановки команд ($()) возвращает ненулевой код выхода.

Обратите внимание, что $() следует использовать для замены команд вместо обратных выходов, см. Это related question.

+0

Получил это. Я надеялся, что смогу избежать проверки чего-либо вне функции «quit» (и обрабатывать все вещи «quit» в одном уникальном месте). Похоже, я могу " t ... Спасибо за ваше объяснение! – DavidL

+0

Добро пожаловать! :) –

2

Рассмотрение отладки сценария показывает проблему. вара = `Foo p1 p2` силы исполнение foo в субоболочке (примечания: увеличение уровня от + до ++ в момент ниже вызова) Исполнение доходов сценария в субоболочке, пока exit 1 достигнуто.exit 1 эффективно завершает возврат к первому скрипту.

$ bash -x exitstuck.sh 
+ logfile=./testQuit_log 
+ rm ./testQuit_log 
++ foo p1 p2    # var=`foo p1 p2` enters subshell '+ -> ++' 
++ '[' 2 -ne 1 ']' 
++ echo 'foo error' 
++ log      # log() called 
++ read data 
++ echo -e 'foo error' 
++ tee -a ./testQuit_log 
++ quit      # quit() called 
++ echo quit 
++ log 
++ read data 
++ echo -e quit 
++ tee -a ./testQuit_log 
++ exit 1     # exit 1 exits subshell, note: '++ -> +' 
+ var='foo error 
quit' 
++ foo p1 
++ '[' 1 -ne 1 ']' 
++ echo res 
+ var2=res 
+ log 
+ read data 
+ echo 'never echo that!' 
+ echo -e 'never echo that!' 
+ tee -a ./testQuit_log 
never echo that! 

Вы можете использовать это в своих интересах, чтобы выполнить то, что вы пытаетесь сделать. Как? Когда exit 1 выходит из подоболочки, он возвращает код выхода 1. Вы можете проверить код выхода в основной сценарий и выйти, как вы намерены:

var=`foo p1 p2` 
if [ $? -eq 1 ]; then 
    exit 
fi 
var2=`foo p1` 

Запуск в отладке еще раз показывает предполагаемую операцию:

$ bash -x exitstuck.sh 
+ logfile=./testQuit_log 
+ rm ./testQuit_log 
++ foo p1 p2 
++ '[' 2 -ne 1 ']' 
++ echo 'foo error' 
++ log 
++ read data 
++ echo -e 'foo error' 
++ tee -a ./testQuit_log 
++ quit 
++ echo quit 
++ log 
++ read data 
++ echo -e quit 
++ tee -a ./testQuit_log 
++ exit 1 
+ var='foo error 
quit' 
+ '[' 1 -eq 1 ']' 
+ exit 
Смежные вопросы