Eu lucrez cu un script bash și vreau să execute o funcție pentru a imprima o valoare de retur:
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $res
}
Cand execut fun2
, nu print "34". De ce este acest caz?
Deși bash are o "întoarcere" declarație, singurul lucru pe care puteți să specificați cu aceasta este funcția's proprii "ieșire" de stare (o valoare între 0 și 255
, 0 sensul "succes"). Atât de "returnare" nu este ceea ce vrei.
Ați putea dori pentru a converti "returnare" declarația de la un "echo", declarație - că modul în funcția de ieșire ar putea fi capturat folosind $()
bretele, care pare a fi exact ceea ce vrei.
Aici este un exemplu:
function fun1(){
echo 34
}
function fun2(){
local res=$(fun1)
echo $res
}
Un alt mod de a obține valoarea de returnare (dacă doriți doar pentru a returna un număr întreg 0-255) e $?
.
function fun1(){
return 34
}
function fun2(){
fun1
local res=$?
echo $res
}
De asemenea, rețineți că puteți folosi valoarea returnată de a utiliza logica booleană ca fun1 || fun2
va rula doar fun2 "dacă" fun1
returnează un 0
valoare. Implicit valoarea de retur este de iesire valoarea din ultima declarație de executat în funcție.
Funcții în Bash nu sunt funcții, cum ar fi în altă limbă; ei're de fapt comenzi. Astfel de funcții sunt folosite ca daca erau binare sau script-uri preluat de la calea ta. Din perspectiva logicii programului ar trebui să fie într-adevăr nici o diferență.
Comenzi Shell sunt conectate prin conducte (aka fluxuri), și nu fundamentale sau definite de utilizator tipuri de date, ca în "reală" limbaje de programare. Nu există nici un astfel de lucru ca o valoare de retur pentru o comanda, poate mai ales pentru că acolo's nici o cale reală de a o declara. S-ar putea să apară pe om pagină, sau --help
ieșire de comandă, dar ambele sunt doar lizibile și, prin urmare, sunt scrise în vânt.
Atunci când o comandă vrea pentru a obține de intrare se citește din fluxul de intrare, sau lista de argumente. În ambele cazuri, siruri de caractere de text trebuie să fie analizat.
Atunci când o comandă vrea să se întoarcă ceva a la "echo", la fluxul de ieșire. Un alt adesea practicat mod este de a stoca o valoare de întoarcere în dedicate, variabile globale. Scrie în fluxul de ieșire este mai clar și mai flexibil, deoarece aceasta poate duce, de asemenea, date binare. De exemplu, vă puteți întoarce o PATĂ de cerneală cu ușurință:
encrypt() {
gpg -c -o- $1 # encrypt data in filename to stdout (asks for a passphrase)
}
encrypt public.dat > private.dat # write function result to file
Ca altii au scris in acest thread, apelantul poate, de asemenea, utilizați comanda înlocuire $()
pentru a captura de ieșire.
În paralel, funcția ar fi "întoarcere" codul de ieșire din gpg(GnuPG). Cred că de codul de ieșire ca un bonus pe care alte limbi nu't au, sau, în funcție de temperament, ca un "Schmutzeffekt" de coajă de funcții. Acest statut este, prin convenție, de la 0 la succes sau un număr întreg în intervalul 1-255 pentru altceva. Pentru a face acest lucru clar:
return` (ca "ieșire") poate lua o valoare dintr-0-255, și alte valori decât 0 nu sunt neapărat erori, cum se afirmă adesea.
Când don't oferi o valoare explicită cu "revenirea" statutul este luat de la ultima comandă într-un Bash/declarație de funcție/de comandă și așa mai departe. Astfel încât există întotdeauna un statut, și "întors" este doar o modalitate ușoară de a oferi.
"Returnare" declarație stabilește codul de ieșire din funcție, la fel ca "ieșire" va face pentru întregul scenariu.
Codul de ieșire pentru ultima comandă este întotdeauna disponibil în $?
variabil.
function fun1(){
return 34
}
function fun2(){
local res=$(fun1)
echo $? # <-- Always echos 0 since the 'local' command passes.
res=$(fun1)
echo $? #<-- Outputs 34
}
Problema cu alte răspunsuri se vor folosi fie un globale, care pot fi suprascrise atunci când mai multe funcții sunt într-un apel lanț, sau "echo", ceea ce înseamnă că funcția nu poate ieșire informații de diagnosticare (vei uita de funcția ta face acest lucru și "rezultat", adică valoarea de returnare, va conține mai multe informații decât apelantul așteaptă, ceea ce duce la bug ciudat), sau "eval" care este mult prea greu și murdari.
Modul corect de a face acest lucru este de a pune la nivelul de sus lucrurile într-o funcție și de a folosi un "local" cu bash's dinamică de definire a domeniului statului. Exemplu:
func1()
{
ret_val=hi
}
func2()
{
ret_val=bye
}
func3()
{
local ret_val=nothing
echo $ret_val
func1
echo $ret_val
func2
echo $ret_val
}
func3
Acest ieșiri
nothing
hi
bye
Dinamică de definire a domeniului înseamnă că ret_val
puncte pentru un obiect diferit în funcție de apelant! Acest lucru este diferit de definire a domeniului lexical, care este ceea ce majoritatea limbajelor de programare utilizat. Aceasta este de fapt un documentate feature, doar ușor de dor, și nu foarte bine explicat, aici este documentația pentru ea (sublinierea este a mea):
Variabile locale funcției pot fi declarate cu cele locale interna. Aceste variabile sunt vizibile numai la funcția de si comenzi invocă.
Pentru cineva cu un C/C++/Python/Java/C#/javascript fundal, aceasta este, probabil, cel mai mare obstacol: funcții în bash nu sunt funcții, acestea sunt comenzi, si se comporta ca atare: ele pot de ieșire la stdout
/`stderr, se pot conducta in/out, se poate returna un cod de ieșire. Practic nu există nici o diferență între a defini o comandă într-un scenariu și de a crea un executabil care poate fi apelat din linia de comandă.
Deci, în loc de a scrie script-ul astfel:
top-level code
bunch of functions
more top-level code
scrie asa:
# define your main, containing all top-level code
main()
bunch of functions
# call main
main
unde main()
declara ret_val
ca "locale" și toate celelalte funcții returnează valori prin ret_val
.
A se vedea, de asemenea, următoarele Unix & Linux întrebare: domeniul de Aplicare al Variabilelor Locale în Coajă Functions.
Un altul, poate chiar mai bună soluție în funcție de situație, este unul postat de tine.teck, care folosește locale -n`.
Îmi place să fac următoarele cazul în care rulează într-un scenariu în cazul în care funcția este definită de:
POINTER= # used for function return values
my_function() {
# do stuff
POINTER="my_function_return"
}
my_other_function() {
# do stuff
POINTER="my_other_function_return"
}
my_function
RESULT="$POINTER"
my_other_function
RESULT="$POINTER"
Îmi place acest lucru, pentru că pot include apoi echo declarații în funcții dacă vreau
my_function() {
echo "-> my_function()"
# do stuff
POINTER="my_function_return"
echo "<- my_function. $POINTER"
}
Ca un add-on pentru alții' excelente de posturi, aici's un articol rezumând aceste tehnici:
Git Bash pe Windows folosind tablouri pentru mai multe valori de returnare
BASH COD:
#!/bin/bash
##A 6-element array used for returning
##values from functions:
declare -a RET_ARR
RET_ARR[0]="A"
RET_ARR[1]="B"
RET_ARR[2]="C"
RET_ARR[3]="D"
RET_ARR[4]="E"
RET_ARR[5]="F"
function FN_MULTIPLE_RETURN_VALUES(){
##give the positional arguments/inputs
##$1 and $2 some sensible names:
local out_dex_1="$1" ##output index
local out_dex_2="$2" ##output index
##Echo for debugging:
echo "running: FN_MULTIPLE_RETURN_VALUES"
##Here: Calculate output values:
local op_var_1="Hello"
local op_var_2="World"
##set the return values:
RET_ARR[ $out_dex_1 ]=$op_var_1
RET_ARR[ $out_dex_2 ]=$op_var_2
}
echo "FN_MULTIPLE_RETURN_VALUES EXAMPLES:"
echo "-------------------------------------------"
fn="FN_MULTIPLE_RETURN_VALUES"
out_dex_a=0
out_dex_b=1
eval $fn $out_dex_a $out_dex_b ##<--Call function
a=${RET_ARR[0]} && echo "RET_ARR[0]: $a "
b=${RET_ARR[1]} && echo "RET_ARR[1]: $b "
echo
##----------------------------------------------##
c="2"
d="3"
FN_MULTIPLE_RETURN_VALUES $c $d ##<--Call function
c_res=${RET_ARR[2]} && echo "RET_ARR[2]: $c_res "
d_res=${RET_ARR[3]} && echo "RET_ARR[3]: $d_res "
echo
##----------------------------------------------##
FN_MULTIPLE_RETURN_VALUES 4 5 ##<---Call function
e=${RET_ARR[4]} && echo "RET_ARR[4]: $e "
f=${RET_ARR[5]} && echo "RET_ARR[5]: $f "
echo
##----------------------------------------------##
read -p "Press Enter To Exit:"
TEMPERATURA DE IEȘIRE:
FN_MULTIPLE_RETURN_VALUES EXAMPLES:
-------------------------------------------
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[0]: Hello
RET_ARR[1]: World
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[2]: Hello
RET_ARR[3]: World
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[4]: Hello
RET_ARR[5]: World
Press Enter To Exit: