Різниця між поверненням і виходом у функціях Bash


429

Яка різниця між returnта exitоператором у функціях Bash щодо кодів виходу?


55
Підказка: введіть help <command>оболонку, щоб отримати інформацію про те, що буде робити вбудована оболонка. У вашому випадку help returnіhelp exit
SiegeX

Відповіді:


318

З man bashна return [n];

Викликає функцію зупиняти виконання та повертати його, що викликає, значення, вказане n. Якщо n опущено, стан повернення - це стан останньої команди, виконаної в тілі функції.

... on exit [n]:

Змусити оболонку вийти зі статусом n. Якщо n опущено, статус виходу є статус останньої виконаної команди. До завершення оболонки виконується пастка на EXIT.

Редагувати:

Згідно з вашим редагуванням питання, що стосується кодів виходу, returnне має нічого спільного з кодами виходу. Вихідні коди призначені для додатків / скриптів , а не для функцій. Тож у цьому відношенні єдиним ключовим словом, яке встановлює вихідний код скрипту (той, який може бути спійманий викликаючою програмою за допомогою $?змінної оболонки) exit.

EDIT 2:

Моє останнє твердження, що стосується exit, викликає деякі коментарі. Це було зроблено для диференціації returnта exitдля розуміння ОП, і насправді в будь- якій точці сценарію програми / оболонки exitє єдиним способом закінчити сценарій кодом виходу до процесу виклику.

Кожна команда виконується в оболонці виробляє локальний «код виходу»: вона встановлює $?змінну до цього коду, і може бути використана з if, &&і іншими операторами умовно виконувати інші команди.

Ці коди виходу (і значення $?змінної) скидаються кожним виконанням команди.

До речі, код виходу останньої команди, виконаної скриптом, використовується як код виходу самого сценарію, як це бачить процес виклику.

Нарешті, функції, коли вони викликаються, виконують функції оболонки щодо кодів виходу. Код виходу функції ( в межах функції) встановлюється за допомогою return. Отже, коли функція return 0виконується, виконання функції закінчується, надаючи код виходу 0.


10
Не зовсім. Це завжди повертає значення з поточної оболонки. Не має значення, ти знаходишся всередині функції чи ні.
Дієго Севілья

10
Прокоментуйте свою редагування: я, можливо, плутаю значення повернення та коди виходу, але func(){ return 50; };func;echo $?повторюється 50. Отже, $?змінна оболонки не здається обмеженою exit.
lecodesportif

8
" $?Розширюється до статусу виходу останнього виконаного переднього плану трубопроводу." Цей вихід може бути з оболонки у формі виклику до exit(або натискання на кінець сценарію) або у формі виклику в returnмежах функції.
SiegeX

11
@lecodesportif: $? поточний процес / скрипт обмежений або exitрезультатом останньої команди, виконаної цим сценарієм. Отже, якщо ваш останній рядок сценарію викликає цю функцію, і ця функція повертає 50, так, то, $?що ви виробляєте до процесу, який викликав вас, дорівнює 50. Однак це не має відношення до return, тому що це обмежено поточним сценарієм. Він може бути повернутий лише в тому випадку, якщо цей виклик функції є останнім реченням сценарію. exitпроте завжди закінчуйте сценарій і повертайте це значення $? щодо процесу виклику .
Дієго Севілья

11
-1 за те, що плутати мене з рядком " returnне має нічого спільного з кодами виходу". Експериментація говорить мені, що між кодом повернення функції та кодом виходу скрипту немає функціональної різниці.
Джек

296

returnпризведе до того, що поточна функція вийде за межі сфери, а exitсценарій закінчиться в тому місці, де вона викликається. Ось приклад програми, яка допоможе пояснити це:

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"

Вихідні дані

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()

17
Гарний приклад. Ви також можете показати значення виходу 1 дюйм $?.
Дієго Севілья

48
Зауважте, що ця функція НЕ надрукує "Ми все ще тут", якщо перед викликом "retfunc" ви додасте "set -e".
Майкл

4
Однак echo fnord | while read x; do exitfunc; done; echo "still here"буде надруковано "все-таки тут". Здається, що whileв цьому сценарії випущений лише підзагін.
трійка

Орієнтовне рішення є, done || exit $?але це некрасиво і не зовсім рівнозначно.
трійка

2
+1 Може бути корисним додати: `` ` returnпризведе до того, що поточна функція або скрипт джерела вийдуть за межі```
Ісаак

56

Я не думаю, що хтось справді повністю відповів на це питання, оскільки не описує, як вони використовуються. Гаразд, я думаю, що ми знаємо, що вихід вбиває скрипт, де б він ніколи не викликався, і ви можете призначити йому статус, такий як вихід або вихід 0 або вихід 7 і так далі. Це може бути використано для визначення того, як скрипт був змушений зупинитися, якщо його викликали іншим сценарієм тощо.

return при виклику поверне значення, вказане для вказівки на поведінку функції, як правило, 1 або 0. Наприклад:

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }

перевірте так:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi

або так:

    isdirectory || echo "not a directory"

У цьому прикладі тест може бути використаний для вказівки, чи був знайдений каталог. зауважте, що нічого після повернення у функції не буде виконано. 0 - це правда, але помилка - 1 в оболонці, відмінна від інших прог.

Для отримання додаткової інформації про функції: http://www.linuxjournal.com/content/return-values-bash-functions

ПРИМІТКА. Функція isdirectory призначена лише для навчальних цілей. Це не повинно бути, як ви виконуєте таку опцію в реальному сценарії.


3
Або просто використовувати test -d $1для досягнення того ж результату. Ніколи не роби if <check> return else return. <check>один буде робити те саме на всіх мовах, які я знаю принаймні.
erikbwork

4
Щоб бути ще більш чітким щодо того, що говорить Ерік: isdirectory() { [ -d "$1" ]; }буде поводитись точно так само, як і у вас тут: Повернення значення за замовчуванням функції оболонки, не доходячи до кінця її коду чи returnаргументів без, - це значення остання команда.
Чарльз Даффі

11
Інші коментатори тут критикують стиль прикладу Майка Q, коли він справді говорить про поведінку returnзаяви. Це правда, що його приклад спрощений і не повинен використовуватися у виробництві. Але це просто, тому він виконує своє завдання просто чудово. Нічого поганого в цьому немає.
Майк S

Дякую Майку S, так, я згоден, що найпростіший приклад найкраще пояснює вихід проти повернення. Інші коментарі, безумовно, дійсні, і їх слід враховувати для більш просунутих баш-кодерів ;-)
Майк Q

1
Деякі можуть сказати, що це не зовсім пов’язано з питанням, але воно стосувалося і відповіло на проблему, яка була у мене, що підштовхнуло мене до пошуку цього питання. :-)
Джессі Стіл

33

Пам'ятайте, що функції є внутрішнім сценарієм і зазвичай повертаються звідки вони були викликані за допомогою оператора return. Виклик зовнішнього скрипта - це зовсім інша справа, і сценарії зазвичай закінчуються оператором виходу.

Різниця "між оператором повернення та виходу у функціях BASH щодо кодів виходу" дуже мала. Обидва повертають статус, а не значення як такі. Статус нуля вказує на успіх, тоді як будь-який інший статус (від 1 до 255) вказує на збій. Оператор return повернеться до скрипту, звідки він був викликаний, тоді як оператор виходу закінчуватиме весь сценарій звідки б він не стикався.

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).

Якщо ваша функція просто закінчується відсутністю оператора return, статус останньої виконаної команди повертається як код статусу (і буде розміщений у $?).

Пам'ятайте, повернення та вихід повертають код статусу від 0 до 255, доступний в $?. Ви не можете нічого іншого заповнити у код статусу (наприклад, повернути "cat"); це не спрацює. Але сценарій може передати 255 різних причин відмови за допомогою кодів статусу.

Ви можете встановити змінні, що містяться в скрипті виклику, або відлунювати результати у функції та використовувати підстановку команд у викличному скрипті; але метою повернення та виходу є передача кодів статусу, а не значень чи результатів обчислень, як можна було очікувати в мові програмування, як C.


25

Іноді, ви запускаєте сценарій, використовуючи .або source.

. a.sh

Якщо ви включите exitв a.sh, він не просто припинить сценарій, але закінчить сеанс оболонки.

Якщо ви включите returnв a.sh, він просто зупиняє обробку сценарію.


1
Але коли я просто запускаю a.sh, я отримую помилку return: can only 'return' from a function or sourced script, що робить його непридатним для загального сценарію.
Пітер - Відновіть Моніку

На найвищому рівні в сценарії жоден з них не підходить у allситуаціях. Використання .або sourceзапуск сценарію в поточній оболонці, а не нерестовина підкошти. Сценарій повинен знати, як його використовувати. Горе користувачеві, який робить це навпаки. Особисто я рекомендую прочитати сценарії, перш ніж запускати їх уперше.
Джессі Чісгольм

3
Дивовижний трюк, який я натрапив, - це використовувати trapфункцію для, ERR EXITа потім зберегти вихідний код невдалої команди, errCode=$?а потім вийти зі скрипту (джерело чи ні), return $errCode || exit $errCodeде ||означає, "якщо я не можу повернутися, тому що мене не знайшли , просто замість цього вийдіть ".
dragon788

6

Простими словами (головним чином для новачків у кодуванні) ми можемо сказати:

`return` : exits the function,
`exit()` : exits the program(called as process while running)

Якщо ви помітили, це дуже просто, але ...,

`return` : is the keyword
`exit()` : is the function

1
У сценарії bash - exitце не більш-менш функція, ніж return. Вони є вбудованими командами. Вони навіть не зарезервовані слова.
Пітер - Відновіть Моніку

6
  • exitприпинити поточний процес ; з кодом виходу або без нього, вважайте це системою більше ніж функцією програми. Зауважте, що при пошуку джерела exitоболонки закінчиться, однак при запуску буде просто exitсценарій.

  • returnз функції поверніться до інструкції після виклику з кодом повернення або без нього. returnнеобов’язково, і це неявно в кінці функції. returnможна використовувати лише всередині функції.

Хочу додати, що, будучи джерелом, exitскрипт із функції не є простим, не вбиваючи оболонку. Я думаю, приклад кращий для сценарію "тестування"

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"

виконуючи наступні дії:

user$ ./test
Whatever is not available
user$

test -і- оболонка закриється.

user$ . ./test
Whatever is not available

тільки testзакінчимо, і підказка покаже.

Рішення полягає в тому, щоб включити потенційно процедуру в (і)

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added

тепер, в обох випадках testбуде лише вихід.


Додаючи (та )додаючи цей блок у підзагін, фактично не виконуючи команду .(джерело) так, як ніби ви зазвичай виконували тестовий скрипт, який знаходиться в підколонці. IOf скрипт не запускається .або sourceтоді у вас фактично є дві підкошти .
Джессі Чисгольм

3

Питання ОП: Яка різниця між оператором повернення та виходу у функціях BASH щодо кодів виходу?

Потрібно уточнити:

  • Завершення операції (return | exit) не потрібно для завершення виконання (функції | оболонки). Функція (оболонка | оболонка) припиняється, коли вона досягне кінця свого списку кодів, навіть не маючи (return | exit) оператора.
  • Оператор (return | exit) не потрібен для передачі значення назад із завершеного (функція | оболонки). У кожному процесі є вбудована змінна $? який завжди має числове значення. Це спеціальна змінна, яку не можна встановити на зразок "? = 1", а встановлювати лише спеціальними способами (див. Нижче *). Значення $? після останньої команди, яка повинна бути виконана у (називається функція | під оболонці) - це значення, яке передається назад (функція виклику | батьківська оболонка). Це правда, чи є остання виконана команда ("return [n]" | "exit [n]") або звичайна ("return" або щось інше, що трапляється останньою командою в коді викликаних функцій).

У наведеному вище списку куль виберіть "(x | y)" або завжди перший елемент, або завжди другий, щоб отримати виписки про функції & return або оболонки та вихід відповідно.

Ясно, що вони обидва мають спільне використання спеціальної змінної $? передавати значення вгору після їх закінчення.

* Тепер для спеціальних способів, що $? можна встановити:

  • Коли викликана функція припиняється і повертається до її виклику, то $? у абонента буде дорівнювати кінцеве значення $? у припиненій функції.
  • Коли батьківська оболонка неявно або явно чекає на одній додатковій оболонці і звільняється після припинення цієї підкошти, тоді $? в батьківській оболонці буде дорівнювати кінцеве значення $? у закінченій підкошті.
  • Деякі вбудовані функції можуть змінювати $? залежно від їх результату. Але деякі ні.
  • Вбудовані функції "повернення" та "вихід", за якими слідує числовий аргумент як $? з аргументом та завершити виконання.

Варто зазначити, що $? можна присвоїти значення за допомогою виклику виходу в допоміжній оболонці:

# (exit 259)
# echo $?
3  

4
Якщо хтось пропустив це, exit 259лунає так, як 3кінцеве значення виходу - один байт. 259 % 256 = 3
Джессі Чизгольм

0

Перш за все, returnце ключове слово, а exitмій друг - функція.

Однак, ось найпростіші пояснення.

return Він повертає значення функції.

exit Він виходить із або покидає поточну оболонку.


Не зовсім! Ви логічно помиляєтесь. Вихід - це функція, а returnключове слово. Повернення набагато більше, ніж просто вихідні коди, тому порівняння не є справедливим.
Ахмад Авайс

Я відредагував це, щоб зробити більш зрозумілим, що я намагався зробити. Дякуємо, що допомогли мені це зробити.
Ахмад Авайс

4
Ні , exitні returnв «ключові слова», або, як Баш ручними називає їх, «зарезервовані слова». Ні одна з них не є "функцією", в значенні функції bash. Обидві вбудовані в команди, в bash lingo. (Там є функція C стандартної бібліотеки називається exit(), і мова програмування Сі має зарезервоване слово return, але ті , які не слід плутати з командами Баша, навіть якщо їх семантика дивно схожа.)
Пітер - відновить Моніку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.