Niejawny zwrot w funkcjach bash?

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

  • Jedną z wad używania return jest ta w przypadku funkcji zdefiniowanych np. f() (...; cmd; return), zapobiega optymalizacji, którą wykonuje kilka powłok, uruchamiając cmd 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, że cmd został zabity, gdy został (większość powłok może ' i tak pobrać te informacje).
  • Zauważ, że z pdksh i niektórymi jego pochodnymi (np. OpenBSD sh lub posh), ' nie potrzebujesz return -- "$?" 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.
  • Dzięki to pomaga, myślę, że nie ' nie rozumiem, jak return x działa inaczej niż exit x … wiem tylko, że return x nie zakończy obecnego procesu.
  • @AlexanderMills Cóż, ' tak jak powiedziałem: return służy do powrotu z funkcji lub skryptu kropkowego. exit robi coś zupełnie innego (kończy proces).
  • tak, to ma sens Myślę, że zaczynam lepiej sobie z tym radzić

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ę od exit 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 i exit są wbudowane, z wyjątkiem return, 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 z return vs exit(n), lub return w porównaniu z sys.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 + glob

    Wię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.

    Dodaj komentarz

    Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *