Valoare returnată într-un Bash funcție

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?

Comentarii la întrebare (3)
Soluția

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.

Comentarii (12)

$(...) surprinde text trimis la stdout de comanda conținute în. "returnare" nu are ieșire la stdout. $? conține codul rezultat de la ultima comanda.

fun1 (){
  return 34
}

fun2 (){
  fun1
  local res=$?
  echo $res
}
Comentarii (2)

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.

Comentarii (2)

"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 $? # 
Comentarii (0)

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

Comentarii (0)

Un alt mod de a realiza acest lucru este numele referințe (necesită Bash 4.3+).

function example {
  local -n VAR=$1
  VAR=foo
}

example RESULT
echo $RESULT
Comentarii (1)

Î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 "
Comentarii (0)

Ca un add-on pentru alții' excelente de posturi, aici's un articol rezumând aceste tehnici:

  • setați o variabilă globală
  • setați o variabilă globală, al cărui nume a trecut la funcția de
  • setați cod de retur (și ridic $?)
  • 'echo' unele date (și ridica-l cu MYVAR=$(myfunction) )

Revenind la Valorile de la Bash Funcții

Comentarii (0)

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  ##
Comentarii (0)