Pracuję ze skryptem bash i chcę uruchomić funkcję, aby wydrukować wartość zwracaną:
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $res
}
Kiedy wykonuję fun2
, nie drukuje „34”. Dlaczego tak jest?
bash
function
return-value
mindia
źródło
źródło
return
w twoim przypadku jest zasadniczo taki sam, jak zexit code
jakiego zakresu0 - 255
. Użyjecho
zgodnie z sugestią @septi. Kody wyjścia można przechwytywać za pomocą$?
.function a() { echo 34; }
function b() { while read data; do echo $data ; done ;}
a | b
Odpowiedzi:
Chociaż bash ma
return
instrukcję, jedyną rzeczą, którą możesz określić, jest własnyexit
status funkcji (wartość pomiędzy 0,0
a255
0 oznacza „sukces”). Więcreturn
nie jest to, czego chcesz.Możesz przekonwertować swoją
return
instrukcję naecho
instrukcję - w ten sposób dane wyjściowe funkcji można przechwycić za pomocą$()
nawiasów klamrowych, co wydaje się dokładnie tym, czego chcesz.Oto przykład:
Innym sposobem uzyskania wartości zwracanej (jeśli chcesz po prostu zwrócić liczbę całkowitą 0–255) jest
$?
.Zauważ też, że możesz użyć wartości zwracanej, aby użyć logiki boolowskiej, tak jak
fun1 || fun2
uruchomi się tylko,fun2
jeślifun1
zwróci0
wartość. Domyślna wartość zwracana to wartość wyjściowa ostatniej instrukcji wykonanej w ramach funkcji.źródło
fun1
a następnie wartość zwracana jest przechowywana w$?
. Chociaż nie poleciłbym tego zrobić…$?
?||
konstrukcji kod wyjścia 0 jest uważany za sukces, a zatem „prawdziwy”. Niezerowa to błąd, a zatem fałsz. Pomyśl ofun1 || fun2
skrócie „jeśli fun1 zwraca sukces lub fun2 zwraca sukces”, a nie operator samych wartości zwracanych.$(...)
przechwytuje tekst wysłany na standardowe wyjście przez zawarte w nim polecenie.return
nie wyświetla wyjścia standardowego.$?
zawiera kod wynikowy ostatniego polecenia.źródło
return
służy do ustawienia,$?
które jestexit status
. W powyższym przykładzie,fun1
„yexit status
byłby34
. Zauważ$(...)
też, że oprócz podanego polecenia przechwytuje także stderr oprócz stdout.Funkcje w Bash nie są funkcjami jak w innym języku; to właściwie polecenia. Funkcje są więc używane tak, jakby były plikami binarnymi lub skryptami pobranymi z Twojej ścieżki. Z punktu widzenia logiki programu naprawdę nie powinno być żadnej różnicy.
Polecenia powłoki są połączone potokami (potokami), a nie podstawowymi lub zdefiniowanymi przez użytkownika typami danych, jak w „prawdziwych” językach programowania. Nie ma czegoś takiego jak wartość zwracana dla polecenia, być może głównie dlatego, że nie ma prawdziwego sposobu na jego zadeklarowanie. Może się to zdarzyć na stronie podręcznika lub na
--help
wyjściu polecenia, ale oba są tylko czytelne dla człowieka i dlatego są zapisywane na wietrze.Gdy polecenie chce uzyskać dane wejściowe, odczytuje je ze strumienia wejściowego lub listy argumentów. W obu przypadkach ciągi tekstowe muszą zostać przeanalizowane.
Gdy polecenie chce zwrócić coś, musi
echo
to zwrócić do strumienia wyjściowego. Innym często praktykowanym sposobem jest przechowywanie wartości zwracanej w dedykowanych zmiennych globalnych. Zapis do strumienia wyjściowego jest wyraźniejszy i bardziej elastyczny, ponieważ może również pobierać dane binarne. Na przykład możesz łatwo zwrócić BLOB:Jak napisali inni w tym wątku, osoba dzwoniąca może również użyć podstawienia polecenia
$()
do przechwycenia wyniku.Równolegle funkcja „zwróciłaby” kod wyjścia
gpg
(GnuPG). Potraktuj kod wyjścia jako bonus, którego nie mają inne języki lub, w zależności od twojego temperamentu, jako „Schmutzeffekt” funkcji powłoki. Status ten, zgodnie z konwencją, wynosi 0 w przypadku powodzenia lub jest liczbą całkowitą z zakresu 1-255 dla czegoś innego. Aby to wyjaśnić:return
(jakexit
) może przyjmować tylko wartość z zakresu 0–255, a wartości inne niż 0 niekoniecznie są błędami, jak się często twierdzi.Jeśli nie podasz wyraźnej wartości,
return
status jest pobierany z ostatniego polecenia w instrukcji / funkcji / poleceniu Bash i tak dalej. Tak więc zawsze jest status ireturn
jest to po prostu łatwy sposób na jego podanie .źródło
return
Instrukcja ustawia kod wyjścia funkcji, tak samo jakexit
zrobi dla całego skryptu.Kod wyjścia dla ostatniego polecenia jest zawsze dostępny w
$?
zmiennej.źródło
Problem z innymi odpowiedziami polega na tym, że albo używają globalnej, którą można zastąpić, gdy kilka funkcji znajduje się w łańcuchu połączeń, lub
echo
co oznacza, że twoja funkcja nie może wyprowadzić informacji diagnostycznych (zapomnisz, że funkcja to robi i „wynik”, tj. Return wartość, będzie zawierać więcej informacji, niż oczekuje Twój rozmówca, co prowadzi do dziwnego błędu) lubeval
jest zbyt ciężkie i zhackowane.Właściwym sposobem na to jest włączenie funkcji najwyższego poziomu w funkcję i użycie
local
reguły dynamicznego określania zakresu przez bash. Przykład:To wychodzi
Dynamiczny zakres oznacza, że
ret_val
wskazuje inny obiekt w zależności od dzwoniącego! Różni się to od zakresu leksykalnego, którego używa większość języków programowania. Jest to właściwie udokumentowana funkcja , po prostu łatwa do pominięcia i niezbyt dobrze wyjaśniona, oto jej dokumentacja (nacisk jest mój):Dla kogoś z tłem C / C ++ / Python / Java / C # / javascript jest to prawdopodobnie największa przeszkoda: funkcje w bash nie są funkcjami, są poleceniami i zachowują się w ten sposób: mogą wysyłać dane do
stdout
/stderr
, mogą wpuszczać / out, mogą zwrócić kod wyjścia. Zasadniczo nie ma różnicy między zdefiniowaniem polecenia w skrypcie a utworzeniem pliku wykonywalnego, który można wywoływać z wiersza poleceń.Zamiast pisać taki skrypt:
napisz to w ten sposób:
gdzie
main()
deklarujeret_val
jakolocal
i wszystkie inne funkcje zwracają wartości przezret_val
.Zobacz także następujące pytanie dotyczące systemów Unix i Linux: Zakres zmiennych lokalnych w funkcjach powłoki .
Inną, być może nawet lepsze rozwiązanie w zależności od sytuacji, jest jednym wysłane przez ya.teck który korzysta
local -n
.źródło
Innym sposobem na osiągnięcie tego jest odwołanie do nazwy (wymaga Bash 4.3+).
źródło
-n <name>=<reference>
robi: sprawia, że nowo utworzona zmienna jest odniesieniem do innej wskazanej przez<reference>
. Dalsze przypisania<name>
są wykonywane na odnośnej zmiennej.Lubię wykonywać następujące czynności, jeśli działa w skrypcie, w którym funkcja jest zdefiniowana:
Podoba mi się to, ponieważ mogę w razie potrzeby dołączyć do moich instrukcji echo
źródło
Jako dodatek do doskonałych postów innych osób, oto artykuł podsumowujący te techniki:
Zwracanie wartości z funkcji Bash
źródło
Git Bash w systemie Windows za pomocą tablic dla wielu zwracanych wartości
KOD PODSTAWOWY:
OCZEKIWANY WYNIK:
źródło