Разница между 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
Python: использовать `yield from` или вернуть генератор?