Różnica między powrotem i wyjściem w funkcjach Bash


429

Jaka jest różnica między instrukcją returni exitw funkcjach Bash w odniesieniu do kodów wyjścia?


55
Protip: wpisz help <command>swoją powłokę, aby uzyskać informacje o tym, co zrobi wbudowana powłoka. W twoim przypadku help returnihelp exit
— SiegeX

Odpowiedzi:


318

Od man bashdnia return [n];

Powoduje, że funkcja przestaje działać i zwraca wartość określoną przez n do swojego obiektu wywołującego. Jeśli pominięto n, zwracany jest status ostatniego polecenia wykonanego w treści funkcji.

... w dniu exit [n]:

Powoduje zamknięcie powłoki ze statusem n. Jeśli n zostanie pominięte, kodem zakończenia jest status ostatniego wykonanego polecenia. Pułapka na EXIT jest wykonywana przed zakończeniem powłoki.

EDYTOWAĆ:

Zgodnie z edycją pytania dotyczącego kodów wyjścia, returnnie ma to nic wspólnego z kodami wyjścia. Kody wyjścia są przeznaczone dla aplikacji / skryptów , a nie funkcji. W związku z tym jedynym słowem kluczowym, które ustawia kod wyjścia skryptu (ten, który może zostać przechwycony przez program wywołujący za pomocą $?zmiennej powłoki) jestexit .

EDYCJA 2:

Moje ostatnie stwierdzenie, które odsyłam, exitpowoduje komentarze. Zostało stworzone w celu odróżnienia returni exitzrozumienia PO, a tak naprawdę w dowolnym punkcie skryptu programu / powłoki,exit jest to jedyny sposób na zakończenie skryptu kodem wyjścia dla procesu wywołującego.

Każda komenda wykonana w powłoce wytwarza lokalną „Kod wyjścia”: ustawia $?zmienną do tego kodu, i może być stosowany z if, &&i inni operatorzy warunkowo wykonywanie innych poleceń.

Te kody wyjścia (i wartość $? zmiennej) są resetowane przy każdym wykonaniu polecenia.

Nawiasem mówiąc, kod wyjścia ostatniego polecenia wykonanego przez skrypt jest używany jako kod wyjścia samego skryptu, jak widać w procesie wywołującym.

Wreszcie, wywołane funkcje działają jak polecenia powłoki względem kodów wyjścia. Kod wyjścia funkcji ( w ramach funkcji) ustawia się za pomocą return. Kiedy więc funkcja return 0jest uruchomiona, wykonywanie funkcji kończy się, dając kod wyjścia 0.


10
Nie dokładnie. Zawsze zwraca wartość z bieżącej powłoki. Nie ma znaczenia, czy jesteś w funkcji, czy nie.
— Diego Sevilla,

10
Skomentuj swoją edycję: Być może mylę wartości zwracane i kody wyjścia, ale func(){ return 50; };func;echo $?echo 50. Zatem $?zmienna powłoki nie wydaje się ograniczona exit.
— lecodesportif,

8
„ $?Rozwija się do statusu wyjścia ostatnio wykonanego rurociągu pierwszego planu.” Wyjście może pochodzić z powłoki w formie wywołania exit(lub uderzenia w koniec skryptu) lub w formie wywołania returnfunkcji.
— SiegeX,

11
@lecodesportif: $? Bieżący proces / skrypt jest ograniczony albo do exitwyniku ostatniego polecenia wykonanego przez ten skrypt. Tak więc, jeśli ostatni wiersz skryptu to wywołanie tej funkcji, a ta funkcja zwraca 50, tak, to $?, co produkujesz do procesu, który cię wezwał, to 50. Jednak to nie ma nic wspólnego z return, ponieważ jest to ograniczony do bieżącego skryptu. Zdarza się, że jest zwracane tylko wtedy, gdy to wywołanie funkcji jest ostatnim zdaniem skryptu. exit, jednak zawsze kończ skrypt i zwracaj tę wartość co $? do procesu wywoływania .
— Diego Sevilla,

11
-1 za pomylenie mnie z linią „ returnnie ma nic wspólnego z kodami wyjścia”. Eksperymentowanie mówi mi, że nie ma funkcjonalnej różnicy między kodem powrotu funkcji a kodem wyjścia skryptu.
— Jack

296

returnspowoduje, że bieżąca funkcja wyjdzie poza zakres, a exitskrypt zakończy się w punkcie, w którym zostanie wywołana. Oto przykładowy program, który pomoże to wyjaśnić:

#!/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"

Wynik

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

17
Niezły przykład. Możesz także wyświetlić wartość wyjściową 1 cala $?.
— Diego Sevilla,

48
Zauważ, że ta funkcja NIE wypisze „Jesteśmy nadal tutaj”, jeśli dodasz „set -e” przed wywołaniem „retfunc”.
— Michael

4
Jednak echo fnord | while read x; do exitfunc; done; echo "still here"wydrukuje „wciąż tutaj”. Wydaje się, że whilew tym scenariuszu wychodzi tylko podpowłoka.
— tripleee

Przybliżone obejście jest done || exit $?jednak brzydkie i nie do końca równoważne.
— tripleee

2
+1 Przydatne może być dodanie: `` returnspowoduje, że bieżąca funkcja lub skrypt źródłowy wykroczą poza zakres ''.
— Izaak

56

Nie sądzę, aby ktokolwiek tak naprawdę w pełni odpowiedział na pytanie, ponieważ nie opisuje, w jaki sposób są one używane. OK. Myślę, że wiemy, że exit zabija skrypt, gdziekolwiek jest on wywoływany, i można przypisać mu status, np. Exit lub exit 0 lub exit 7 i tak dalej. Można to wykorzystać do ustalenia, w jaki sposób skrypt został zmuszony do zatrzymania, jeśli został wywołany przez inny skrypt itp. Wystarczy przy wyjściu.

return, gdy zostanie wywołany, zwróci wartość określoną w celu wskazania zachowania funkcji, zwykle 1 lub 0. Na przykład:

    #!/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"
    }

sprawdź tak:

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

lub tak:

    isdirectory || echo "not a directory"

W tym przykładzie test można wykorzystać do wskazania, czy katalog został znaleziony. zauważ, że cokolwiek po zwrocie nie zostanie wykonane w funkcji. 0 to prawda, ale fałsz to 1 w powłoce, różny od innych języków prog.

Aby uzyskać więcej informacji na temat funkcji: http://www.linuxjournal.com/content/return-values-bash-functions

UWAGA: Funkcja isdirectory służy wyłącznie do celów instruktażowych. Nie powinno tak być w przypadku wykonywania takiej opcji w prawdziwym skrypcie.


3
Lub po prostu użyj, test -d $1aby osiągnąć ten sam wynik. Nigdy nie rób if <check> return else return. <check>sam zrobi to samo we wszystkich językach, które znam przynajmniej.
— erikbwork

4
Aby być jeszcze bardziej wyraźnym na temat tego, co mówi erik: isdirectory() { [ -d "$1" ]; }zachowa się dokładnie tak samo, jak tutaj: Domyślna wartość zwracana przez funkcję powłoki, czy to po osiągnięciu końca kodu, czy też returnbez argumentów, jest wartością parametru ostatnie polecenie.
— Charles Duffy

11
Inni komentatorzy tutaj krytykują styl przykładu Mike'a Q, kiedy tak naprawdę mówi o zachowaniu returnwypowiedzi. To prawda, że ​​jego przykład jest uproszczony i nie może być wykorzystywany w produkcji. Ale to proste, więc dobrze spełnia swoje zadanie. Nie ma w tym nic złego.
— Mike S

Dzięki Mike S, tak, zgadzam się, że najprostszy przykład najlepiej wyjaśnia wyjście vs powrót. Pozostałe komentarze są z pewnością prawidłowe i należy je rozważyć w przypadku bardziej zaawansowanych koderów bash ;-)
— Mike Q

1
Niektórzy mogą powiedzieć, że nie jest to dokładnie związane z pytaniem, ale dotyczyło i odpowiedziało na mój problem, który doprowadził mnie do znalezienia tego pytania. :-)
— Jesse Steele

33

Pamiętaj, że funkcje są wewnętrzne dla skryptu i zwykle zwracają skąd zostały wywołane za pomocą instrukcji return. Wywołanie zewnętrznego skryptu to zupełnie inna sprawa, a skrypty zwykle kończą się instrukcją exit.

Różnica „między instrukcją return i exit w funkcjach BASH w odniesieniu do kodów wyjścia” jest bardzo niewielka. Oba zwracają status, a nie same wartości . Status zero oznacza sukces, a każdy inny status (od 1 do 255) oznacza awarię. Instrukcja return powróci do skryptu, z którego została wywołana, a instrukcja exit zakończy cały skrypt od momentu napotkania.

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

Jeśli funkcja kończy się po prostu bez instrukcji return, status ostatniego wykonanego polecenia jest zwracany jako kod statusu (i zostanie umieszczony w $? ).

Pamiętaj, zwróć i wyjdź, zwróć kod stanu od 0 do 255, dostępny w $? . Nie możesz wstawić niczego innego do kodu statusu (np. Zwróć „cat”); to nie zadziała. Ale skrypt może przekazać 255 różnych przyczyn niepowodzenia za pomocą kodów stanu.

Możesz ustawić zmienne zawarte w skrypcie wywołującym lub echo skutkuje funkcją i użyć substytucji poleceń w skrypcie wywołującym; ale celem powrotu i wyjścia jest przekazanie kodów statusu, a nie wartości lub wyników obliczeń, jak można się spodziewać w języku programowania takim jak C.


25

Czasami uruchamiasz skrypt za pomocą .lub source.

. a.sh

Jeśli dodasz exitdo a.shniego, nie tylko zakończy on skrypt, ale zakończy sesję powłoki.

Jeśli obejmują returnw a.sh, po prostu przestaje przetwarzać skrypt.


1
Ale po uruchomieniu a.sh pojawia się błąd return: can only 'return' from a function or sourced script, który sprawia, że ​​nie nadaje się do ogólnego skryptu.
— Peter - przywróć Monikę

Na najwyższym poziomie w skrypcie żadna nie jest odpowiednia w allsytuacjach. Użycie .lub sourceuruchomienie skryptu w bieżącej powłoce zamiast odradzania podpowłoki. Skrypt musi wiedzieć, jak go używać. Biada użytkownikowi, który robi to odwrotnie. Osobiście polecam przeczytanie skryptów przed uruchomieniem ich po raz pierwszy.
— Jesse Chisholm

3
Niesamowita sztuczka, z jaką się spotkałem, to użyć trapfunkcji, ERR EXITa następnie najpierw zapisać kod wyjścia nieudanego polecenia, errCode=$?a następnie wyjść ze skryptu ( źródłowego lub nie), return $errCode || exit $errCodegdzie ||oznacza „jeśli nie mogę wrócić, ponieważ nie otrzymałem źródła , po prostu wyjdź zamiast ".
— dragon788

6

W prostych słowach (głównie dla początkujących w kodowaniu) możemy powiedzieć:

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

Również jeśli zauważyłeś, jest to bardzo proste, ale ...

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

1
W skrypcie bash exitnie jest mniej więcej funkcją return. Są to wbudowane polecenia. Nie są to nawet słowa zastrzeżone.
— Peter - Przywróć Monikę

6
  • exitzakończyć bieżący proces ; z kodem wyjścia lub bez niego, uważaj to za system bardziej niż funkcję programu. Zauważ, że podczas sourcingu exitzakończy działanie powłoki, jednak po uruchomieniu exitskryptu.

  • returnz funkcji wróć do instrukcji po wywołaniu, z kodem powrotu lub bez niego. returnjest opcjonalny i niejawny na końcu funkcji. returnmoże być używany tylko wewnątrz funkcji.

Chcę dodać, że podczas pozyskiwania exitskrypt nie jest łatwy do wykonania z poziomu funkcji bez zabicia powłoki. Myślę, że lepszy jest przykład skryptu „testowego”

#!/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"

wykonując następujące czynności:

user$ ./test
Whatever is not available
user$

test i skorupa się zamknie.

user$ . ./test
Whatever is not available

tylko test zakończy się i pojawi się monit.

Rozwiązaniem jest zawarcie potencjalnie procedury w (i)

#!/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

teraz w obu przypadkach tylko testwyjdzie.


Dodanie (i )umieszcza ten blok w podpowłoce, skutecznie nie wykonując polecenia .(źródłowego), tak jakbyś normalnie uruchomił skrypt testowy, który znajduje się w podpowłoce. Jeśli skrypt nie jest uruchamiany z, .lub sourcewtedy efektywnie masz 2 podpowłoki.
— Jesse Chisholm

3

Pytanie OP: Jaka jest różnica między instrukcją return i exit w funkcjach BASH w odniesieniu do kodów wyjścia?

Po trzecie, potrzebne jest pewne wyjaśnienie:

  • Instrukcja (return | exit) nie jest wymagana do zakończenia wykonywania (powłoki | funkcji). (Funkcja | powłoka) zakończy się, gdy osiągnie koniec listy kodów, nawet bez instrukcji (return | exit).
  • Instrukcja (return | exit) nie jest wymagana do zwrócenia wartości z zakończonego (funkcja | shell). Każdy proces ma wbudowaną zmienną $? która zawsze ma wartość liczbową. Jest to specjalna zmienna, której nie można ustawić jak „? = 1”, ale można ją ustawić tylko w specjalny sposób (patrz poniżej *). Wartość $? po ostatnim poleceniu, które ma zostać wykonane w (nazywanej funkcji | powłoce dodatkowej), jest wartość przekazywana z powrotem do (funkcji wywołującej | powłoki nadrzędnej). Jest tak niezależnie od tego, czy ostatnim wykonanym poleceniem jest („return [n]” | ”exit [n]”), czy zwykły („return”, czy coś innego, co może być ostatnim poleceniem w wywoływanym kodzie funkcji.

Na powyższej liście punktorów wybierz z „(x | y)” albo zawsze pierwszy element, albo zawsze drugi element, aby uzyskać instrukcje dotyczące odpowiednio funkcji i powrotu lub powłok i wyjścia.

Oczywiste jest, że oboje mają wspólne zastosowanie specjalnej zmiennej $? przekazywać wartości w górę po ich zakończeniu.

* Teraz specjalne sposoby, że $? może być ustawiony:

  • Kiedy wywoływana funkcja kończy się i wraca do swojego wywołującego, to $? w dzwoniącym będzie równa końcowej wartości $? w funkcji zakończonej.
  • Gdy powłoka nadrzędna domyślnie lub jawnie czeka na pojedynczą podpowłokę i zostaje zwolniona przez zakończenie tej podpowłoki, wówczas $? w powłoce nadrzędnej będzie równa końcowej wartości $? w zakończonej podpowłoce.
  • Niektóre wbudowane funkcje mogą modyfikować $? w zależności od ich wyniku. Ale niektórzy nie.
  • Wbudowane funkcje „return” i „exit”, po których następuje argument liczbowy zarówno $? z argumentem i zakończ wykonywanie.

Warto zauważyć, że $? można przypisać wartość, wywołując exit w podpowłoce, tak jak to:

# (exit 259)
# echo $?
3  

4
W przypadku, gdy niektórzy go przegapili, wyświetl exit 259echo, 3ponieważ końcowa wartość wyjściowa to jeden bajt. 259 % 256 = 3
— Jesse Chisholm

0

Przede wszystkim returnjest słowem kluczowym iexit mój przyjaciel jest funkcją.

To powiedziawszy, oto najprostsze wyjaśnienie.

return Zwraca wartość z funkcji.

exit Wychodzi z bieżącej powłoki lub ją opuszcza.


Nie całkiem! Logicznie się mylisz. Wyjście jest funkcją, podczas gdy returnsłowem kluczowym. Zwrot to znacznie więcej niż tylko kody wyjścia, dlatego porównanie nie jest sprawiedliwe.
— Ahmad Awais

Napisałem to, aby wyjaśnić, co chciałem wyjaśnić. Dzięki, że mi pomogłeś.
— Ahmad Awais

4
Ani exitteż nie returnsą „słowami kluczowymi”, ani, jak to nazywa podręcznik bash, „słowami zastrzeżonymi”. Żaden z nich nie jest również „funkcją” w sensie funkcji bash. Oba są wbudowanymi poleceniami w języku bash. (Wywoływana jest standardowa funkcja biblioteki C exit(), a język programowania C ma słowo zastrzeżone return, ale nie należy ich mylić z poleceniami bash, mimo że ich semantyka jest dziwnie podobna.)
— Peter - Przywróć Monicę
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.