Разница между return и exit в функциях Bash
В чем разница между return
и exit
в функциях Bash с точки зрения кодов завершения?
5 ответ(ов)
Функция return [n]
в Bash останавливает выполнение функции и возвращает значение, указанное параметром n
, вызывающему коду. Если этот параметр опущен, возвращается код состояния последней выполненной команды в теле функции.
С другой стороны, команда exit [n]
завершает выполнение оболочки с кодом состояния n
. Если n
не указан, код выхода будет равен коду состояния последней выполненной команды. Примечание: перед завершением оболочки выполняется команда, определенная с помощью trap
на событие EXIT
.
EDIT:
Что касается кодов выхода, команда return
не имеет отношения к кодам выхода. Коды выхода предназначены для приложений/скриптов, а не для функций. Таким образом, единственное ключевое слово, которое устанавливает код выхода скрипта (который может быть захвачен вызывающей программой через переменную $?
), — это exit
.
EDIT 2:
Мое предыдущее утверждение о exit
вызвало несколько комментариев. Оно было сделано для того, чтобы различить return
и exit
для лучшего понимания вопроса. На самом деле, на любом этапе выполнения программы/скрипта, exit
— это единственный способ завершить скрипт с кодом выхода для вызывающего процесса.
Каждая команда, выполняемая в оболочке, производит локальный «код выхода»: он устанавливает переменную $?
в этот код и может использоваться с if
, &&
и другими операторами для условного выполнения других команд.
Эти коды выхода (и значение переменной $?
) сбрасываются при каждом выполнении команды.
Кстати, код выхода последней выполненной командой в скрипте используется как код выхода самого скрипта, как это видно вызывающим процессом.
В конечном итоге функции, при вызове, ведут себя как команды оболочки в отношении кодов выхода. Код выхода функции (внутри функции) устанавливается с помощью команды return
. Таким образом, когда в функции выполняется return 0
, выполнение функции завершается с кодом выхода 0.
Функция return
приводит к тому, что текущая функция выходит из области видимости, в то время как exit
завершает выполнение скрипта в точке, где она была вызвана. Вот пример программы, который поможет это объяснить:
#!/bin/bash
retfunc()
{
echo "это retfunc()"
return 1
}
exitfunc()
{
echo "это exitfunc()"
exit 1
}
retfunc
echo "Мы все еще здесь"
exitfunc
echo "Мы никогда не увидим это"
Вывод
$ ./test.sh
это retfunc()
Мы все еще здесь
это exitfunc()
В этом примере, когда вызывается retfunc
, она выполняет свою работу и возвращает управление назад, позволяя продолжать выполнение скрипта, что позволяет вывести "Мы все еще здесь". Однако, когда вызывается exitfunc
, она завершает выполнение всего скрипта, и строка "Мы никогда не увидим это" никогда не будет выполнена.
Разница между операторами return
и exit
в функциях Bash относительно кодов завершения действительно очень мала. Оба возвращают статус, но не значения в привычном смысле. Статус 0 указывает на успешное выполнение, в то время как любой другой статус (от 1 до 255) говорит о сбое. Оператор return
возвращает управление в скрипт, откуда была вызвана функция, тогда как оператор exit
завершает весь скрипт, где бы он ни находился.
Вот примеры:
return 0 # Возвращает в место вызова функции. $? содержит 0 (успех).
return 1 # Возвращает в место вызова функции. $? содержит 1 (сбой).
exit 0 # Полностью завершает скрипт. $? содержит 0 (успех).
exit 1 # Полностью завершает скрипт. $? содержит 1 (сбой).
Если ваша функция просто завершается без оператора return
, статус последней выполненной команды будет возвращён в качестве кода завершения (и окажется в $?
).
Помните, что операторы return
и exit
возвращают коды статуса от 0 до 255, доступные в $?
. Вы не можете передать что-либо другое через код статуса (например, return "cat"
); это не сработает. Однако скрипт может вернуть 255 различных причин сбоя, используя коды статуса.
Вы можете устанавливать переменные, находящиеся в вызывающем скрипте, или использовать echo
в функции и затем подменять результаты в вызывающем скрипте; но цель операторов return
и exit
— передавать коды статуса, а не значения или результаты вычислений, как это можно ожидать в языках программирования, таких как C.
При выполнении скрипта с помощью .
или source
, например:
. a.sh
Если в a.sh
будет команда exit
, это приведёт не только к завершению выполнения скрипта, но и к окончанию вашей сессии в оболочке.
С другой стороны, если в a.sh
использовать return
, то это просто остановит выполнение скрипта, и ваша оболочка продолжит работать.
Поэтому, если вам нужно, чтобы скрипт завершался, но не выходил из оболочки, используйте return
.
Вопрос от автора: Какова разница между операторами return и exit в функциях BASH с точки зрения кодов выхода?
Прежде всего, необходимо прояснить несколько моментов:
Операторы (return|exit) не обязательны для завершения выполнения (функции|шелла). (Функция|Шелл) завершится, когда достигнет конца своего списка кода, даже без оператора (return|exit).
Операторы (return|exit) не обязательны для передачи значения обратно от завершившейся (функции|шелла). Каждый процесс имеет встроенную переменную
$?
, которая всегда содержит числовое значение. Это специальная переменная, которую нельзя установить напрямую, например, "?=1"; она устанавливается только особым образом (см. ниже *).Значение
$?
после последней выполняемой команды в (вызванной функции | подсистеме) — это значение, которое передается обратно (вызвавшей функции | родительскому шеллу). Это верно, независимо от того, была ли последней выполненной командой ("return [n]"| "exit [n]") или простая ("return" или что-то еще, что оказалось последней командой в коде вызванной функции.
В приведенном выше списке выберите из "(x|y)" либо всегда первый пункт, либо всегда второй, чтобы получить утверждения о функциях и return, или о шеллах и exit соответственно.
Ясно, что оба оператора используют специальную переменную $?
для передачи значений вверх после завершения.
- Теперь о специальных способах, которыми можно установить
$?
:
- Когда вызванная функция завершает выполнение и возвращается к своему вызывающему, тогда
$?
в вызывающем будет равен итоговому значению$?
в завершившейся функции. - Когда родительский шелл явно или неявно ожидает завершения одной подсистемы и освобождается после ее завершения, то
$?
в родительском шелле будет равно итоговому значению$?
в завершившейся подсистеме. - Некоторые встроенные функции могут изменять
$?
в зависимости от своего результата. Но некоторые этого не делают. - Встроенные функции "return" и "exit", когда за ними следует числовой аргумент, устанавливают
$?
на свое значение аргумента и завершают выполнение.
Стоит отметить, что $?
может быть назначено значение путем вызова exit в подсистеме, как в следующем примере:
# (exit 259)
# echo $?
3
Как вернуть строковое значение из функции Bash
Как в Bash-скрипте выйти из всего скрипта при выполнении определенного условия?
Как передать все аргументы, переданные в Bash-скрипт, в мою функцию?
Передача параметров в функцию Bash
Как получить возвращаемое значение из потока?