Powiedzmy, że mam taką funkcję bash:
gmx(){ echo "foo"; }
czy ta funkcja będzie niejawnie zwrócić wartość wyjściową polecenia echo
, czy użycie powrotu jest konieczne?
gmx(){ echo "foo"; return $? }
Zakładam, że sposób bash działa, kodem zakończenia ostatniego polecenia funkcji bash jest ten, który zostaje „zwrócony”, ale nie jest w 100% pewny.
Odpowiedź
return
wykonuje wyraźny zwrot z funkcji powłoki lub„ skryptu kropkowego ”(skryptu źródłowego). Jeśli return
nie zostanie wykonane, na końcu funkcji powłoki lub skryptu kropkowego wykonywany jest niejawny zwrot.
Jeśli return
jest wykonywany bez parametru, jest to równoważne zwróceniu statusu wyjścia ostatnio wykonanego polecenia.
Tak działa return
we wszystkich POSIX powłoki.
Na przykład
gmx () { echo "foo" return "$?" }
jest zatem równoważne z
gmx () { echo "foo" return }
czyli to samo co
gmx () { echo "foo" }
Ogólnie rzecz biorąc, bardzo rzadko trzeba używać $?
w ogóle. Jest to naprawdę potrzebne tylko wtedy, gdy chcesz zapisać ją do przyszłego użytku, na przykład, jeśli chcesz wielokrotnie zbadać jej wartość (w takim przypadku przypiszesz jej wartość do zmiennej i wykonasz serię testów na tej zmiennej).
Komentarze
Odpowiedź
Ze strony podręcznika bash(1)
:
Po wykonaniu, kod zakończenia funkcji jest kodem zakończenia ostatniego polecenia wykonanego w treści.
Komentarze
- racja, a konsekwencją może być to, że instrukcja return to nic innego jak status wyjścia?
- Myślę, że
return
to polecenie wbudowane – chociażreturn 1
różni się odexit 1
itd., Więc - ” return [n]: Powoduje, że funkcja zatrzymuje wykonywanie i zwraca wartość określoną przez n do jej wywołującego. Jeśli pominięto n, zwracany jest stan ostatniego polecenia wykonanego w treści funkcji. ” (ibid) Tak więc
return
wymusza status wyjścia funkcji na określoną wartość, jeśli została określona. - @AlexandwrMills Tak,
return
iexit
są wbudowane, z wyjątkiemreturn
, których można używać tylko w ramach funkcji. Możesz ' zakończyć skrypt za pomocąreturn
. Status wyjścia to wartość zwracana przez polecenie.return
to polecenie, które zwraca tę wartość. Zatem instrukcja ” to nic innego jak status wyjścia ” jest po prostu niedokładna. Jeden to wartość, a drugi to polecenie plus wartość. - @AlexanderMills,
return
zwraca z funkcji,exit
wychodzi z całej powłoki. Jest ' jest dokładnie taki sam jak w, powiedzmy C zreturn
vsexit(n)
, lubreturn
w porównaniu zsys.exit()
w Pythonie.
Odpowiedź
Dodam tylko kilka uwag ostrzegawczych do już udzielonych odpowiedzi:
-
Mimo że
return
ma bardzo szczególne znaczenie dla powłoki, z punktu widzenia składni jest to polecenie wbudowane powłoki i instrukcja return jest przetwarzane jak każde inne proste polecenie. Oznacza to więc, że podobnie jak w przypadku każdego innego polecenia,$?
bez cytowania będzie podlegać podziałowi + globWięc musisz zacytować, że
$?
, aby tego uniknąć:return "$?"
-
return
zwykle nie „nie akceptuje żadnej opcji (ksh93
” s akceptuje zwykłe--help
,--man
,--author
… chociaż). Jedynym oczekiwanym argumentem (opcjonalnym) jest kod powrotu. Zakres akceptowanych kodów powrotu jest różny od powłoki do powłoki i czy jakakolwiek wartość poza 0..255 jest właściwie odzwierciedlona w
także różni się w zależności od powłoki. Zobacz Domyślny kod zakończenia po zakończeniu procesu? , aby dowiedzieć się więcej.
Większość powłok akceptuje liczby ujemne (w końcu argument przekazany do _exit()
/ exitgroup()
jest wywołaniem systemowym int
, więc z wartościami obejmującymi co najmniej – 2 31 do 2 31 -1, więc ma sens tylko, że powłoki akceptują ten sam zakres dla swoich funkcji).
Większość powłok używa waitpid()
i co. API w celu pobrania tego statusu wyjścia, ale w takim przypadku jest on skracany do liczby z zakresu od 0 do 255, gdy jest przechowywany w $?
. Mimo że wywołanie funkcji nie obejmuje tworzenia procesu i używa waitpid()
do pobrania jego statusu wyjścia, ponieważ wszystko odbywa się w tym samym procesie, wiele powłok również naśladuje to waitpid()
zachowanie podczas wywoływania funkcji. Co oznacza, że nawet jeśli wywołasz return
z wartością ujemną, $?
będzie zawierać liczbę dodatnią.
Teraz wśród tych powłok, których return
akceptuje liczby ujemne (ksh88, ksh93, bash, zsh, pdksh i pochodne inne niż mksh, yash), jest kilka ( pdksh i yash), które wymagają zapisania jako return -- -123
, w przeciwnym razie -123
jest traktowane jako trzy -1
, -2
, -3
nieprawidłowe opcje.
Jako pdksh i jego de rywalizacje (takie jak OpenBSD sh
lub posh
) zachowują liczbę ujemną w $?
, to znaczy że wykonanie return "$?"
nie powiedzie się, jeśli $?
zawiera liczbę ujemną (co miałoby miejsce, gdyby ostatnie polecenie uruchomienia było funkcją zwracającą liczbę ujemną ).
Więc return -- "$?"
byłoby lepsze w tych powłokach. Należy jednak zauważyć, że chociaż obsługiwana przez większość powłok, składnia ta nie jest zgodna z POSIX i w praktyce nie jest obsługiwana przez mksh
i pochodne ash.
Podsumowując, z powłokach opartych na pdksh, możesz używać liczb ujemnych w argumentach funkcji, ale jeśli to zrobisz, return "$@"
nie zadziała. W innych powłokach return "$@"
będzie działać i należy unikać używania liczb ujemnych (lub liczb spoza 0..255) jako argumentów funkcji return
.
We wszystkich znanych mi powłokach wywołanie return
z wnętrza podpowłoki działającej wewnątrz funkcji spowoduje zamknięcie podpowłoki (z podanym kodem zakończenia, jeśli istnieje, lub z ostatnim poleceniem run), ale w innym przypadku nie spowoduje powrotu z funkcji (dla mnie nie jest jasne, czy POSIX daje tę gwarancję, niektórzy twierdzą, że exit
powinno być używane zamiast podpowłok wyjścia funkcje wewnętrzne). Na przykład
f() { (return 3) echo "still inside f. Exit status: $?" } f echo "f exit status: $?"
wyświetli:
still inside f. Exit status: 3 f exit status: 0
Odpowiedź
Tak, niejawna wartość zwracana funkcji to kod zakończenia ostatniej wykonanej funkcji . Jest to również prawdziwe w każdym momencie każdego skryptu powłoki. W dowolnym momencie sekwencji wykonywania skryptu aktualny kod zakończenia jest kodem zakończenia ostatniego wykonanego polecenia. Nawet polecenie wykonywane jako część przypisania zmiennej: var=$(exit 34)
. Różnica w przypadku funkcji polega na tym, że funkcja może zmienić status wyjścia na koniec wykonywania funkcji.
Alternatywnym sposobem zmiany „obecnego statusu wyjścia” jest uruchomienie podpowłoki i wyjście z niej za pomocą dowolny potrzebny stan wyjścia:
$ $(exit 34) $ echo "$?" 34
I tak, stan wyjścia rozwinięcie muszą być cytowane:
$ IFS="123" $ $(exit 34) $ echo $? 4
(exit 34)
też działa.
Niektórzy mogą twierdzić, że bardziej niezawodną konstrukcją powinno być $(return 34)
, a wyjście powinno „wyjść” z wykonywanego skryptu. Ale $(return 34)
nie działa z żadną wersją bash. Dlatego nie jest przenośny.
Najbezpieczniejszym sposobem ustawienia statusu wyjścia jest użycie go w takiej postaci, w jakiej został zaprojektowany, zdefiniowanie i return
z funkcji :
exitstatus(){ return "${1:-"$?"}"; }
A więc na końcu funkcji. jest to dokładnie równoznaczne z brakiem niczego lub return
lub return "$?"
. Koniec funkcji nie musi oznaczać „ostatniej linii kodu funkcji”.
#!/bin/sh exitstatus(){ a="${1:-"$?"}"; return "$a"; } gmx(){ if [ "$1" = "one" ]; then printf "foo "; exitstatus 78 return "$?" elif [ "$1" = "two" ]; then printf "baz "; exitstatus 89 return else printf "baz "; exitstatus 90 fi }
Wypisze:
$ ./script foo 78 baz 89 baz 90
Jedynym praktycznym zastosowaniem "$?"
jest wydrukowanie jego wartości: echo "$?"
lub zapisanie w zmiennej (ponieważ jest to wartość efemeryczna i zmienia się po każdym wykonaniu polecenia): exitstatus=$?
(pamiętaj, aby cytować zmienną w poleceniach takich jak export EXITSTATUS="$?"
.
W poleceniu return
prawidłowy zakres wartości wynosi zwykle od 0 do 255, ale pamiętaj, że wartości 126 + n
są używane przez niektóre powłoki do sygnalizowania specjalnego statusu wyjścia, więc generalnym zaleceniem jest użycie 0-125.
return
jest ta w przypadku funkcji zdefiniowanych np.f() (...; cmd; return)
, zapobiega optymalizacji, którą wykonuje kilka powłok, uruchamiająccmd
w tym samym procesie co podpowłoka. W przypadku wielu powłok oznacza to również, że status wyjścia funkcji nie ' nie zawiera informacji, żecmd
został zabity, gdy został (większość powłok może ' i tak pobrać te informacje).sh
lubposh
), ' nie potrzebujeszreturn -- "$?"
jeśli był szansa, że ostatnie polecenie było funkcją, która zwróciła liczbę ujemną.mksh
(również oparty na pdksh) zabrania funkcjom zwracania wartości ujemnych.return x
działa inaczej niżexit x
… wiem tylko, żereturn x
nie zakończy obecnego procesu.return
służy do powrotu z funkcji lub skryptu kropkowego.exit
robi coś zupełnie innego (kończy proces).