Valeur renvoyée dans une fonction Bash

Je travaille avec un script bash et je veux exécuter une fonction pour imprimer une valeur de retour:

function fun1(){ return 34 } function fun2(){ local res=$(fun1) echo $res } 

Quand fun2 , cela n’imprime pas “34”. pourquoi est-ce le cas?

    Bien que bash ait une déclaration de return , la seule chose que vous pouvez spécifier avec cela est le propre statut de exit la fonction (une valeur entre 0 et 255 , 0 signifiant “succès”). Donc, le return n’est pas ce que vous voulez.

    Vous voudrez peut-être convertir votre déclaration de return en une déclaration echo – de cette manière, votre sortie de fonction pourrait être capturée à l’aide d’accolades $() , ce qui semble être exactement ce que vous voulez.

    Voici un exemple:

     function fun1(){ echo 34 } function fun2(){ local res=$(fun1) echo $res } 

    Une autre façon d’obtenir la valeur de retour (si vous voulez juste retourner un entier compris entre 0 et 255) est $? .

     function fun1(){ return 34 } function fun2(){ fun1 local res=$? echo $res } 

    Notez également que vous pouvez utiliser la valeur de retour pour utiliser la logique booléenne comme fun1 || fun2 fun1 || fun2 que si fun1 renvoie une valeur 0 . La valeur de retour par défaut est la valeur de sortie de la dernière instruction exécutée dans la fonction.

    $(...) capture le texte envoyé à stdout par la commande contenue dans. return ne sort pas à la sortie standard. $? contient le code de résultat de la dernière commande.

     fun1 (){ return 34 } fun2 (){ fun1 local res=$? echo $res } 

    Les fonctions dans Bash ne sont pas des fonctions comme dans d’autres langues; ce sont en fait des commandes. Les fonctions sont donc utilisées comme s’il s’agissait de binarys ou de scripts extraits de votre chemin. Du sharepoint vue de la logique de votre programme, il ne devrait y avoir aucune différence.

    Les commandes shell sont connectées par des canaux (ou stream), et non par des types de données fondamentaux ou définis par l’utilisateur, comme dans les “vrais” langages de programmation. Il n’y a pas de valeur de retour pour une commande, peut-être principalement parce qu’il n’y a pas de moyen de le déclarer. Cela peut se produire sur la page de manuel ou sur la sortie --help de la commande, mais les deux ne sont lisibles que par l’homme et sont donc écrites dans le vent.

    Lorsqu’une commande veut obtenir une entrée, elle la lit dans son stream d’entrée ou dans la liste d’arguments. Dans les deux cas, les chaînes de texte doivent être analysées.

    Lorsqu’une commande veut retourner quelque chose, elle doit lui faire echo dans son stream de sortie. Une autre méthode souvent utilisée consiste à stocker la valeur de retour dans des variables globales dédiées. L’écriture dans le stream de sortie est plus claire et plus flexible, car elle peut également prendre en charge des données binarys. Par exemple, vous pouvez retourner un BLOB facilement:

     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 

    Comme d’autres l’ont écrit dans ce thread, l’appelant peut également utiliser la substitution de commandes $() pour capturer la sortie.

    Parallèlement, la fonction “renverrait” le code de sortie de gpg (GnuPG). Considérez le code de sortie comme un bonus que les autres langues n’ont pas, ou, selon votre tempérament, un “Schmutzeffekt” des fonctions du shell. Cet état est, par convention, égal à 0 en cas de succès ou à un nombre entier compris entre 1 et 255 pour autre chose. Pour que cela soit clair: return (comme exit ) ne peut prendre qu’une valeur de 0 à 255, et les valeurs autres que 0 ne sont pas nécessairement des erreurs, comme cela est souvent affirmé.

    Lorsque vous ne fournissez pas de valeur explicite avec return le statut est extrait de la dernière commande dans une instruction / fonction / commande Bash, etc. Il y a donc toujours un statut et le return est juste un moyen facile de le fournir.

    L’instruction return définit le code de sortie de la fonction, de la même façon que exit pour tout le script.

    Le code de sortie de la dernière commande est toujours disponible dans le $? variable.

     function fun1(){ return 34 } function fun2(){ local res=$(fun1) echo $? # <-- Always echos 0 since the 'local' command passes. res=$(fun1) echo $? #<-- Outputs 34 } 

    J’aime faire ce qui suit si vous exécutez un script dans lequel la fonction est définie:

     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" 

    J’aime ça, car je peux alors inclure des instructions echo dans mes fonctions si je veux

     my_function() { echo "-> my_function()" # do stuff POINTER="my_function_return" echo "<- my_function. $POINTER" } 

    En complément des excellentes publications des autres, voici un article résumant ces techniques:

    • définir une variable globale
    • définir une variable globale dont vous avez transmis le nom à la fonction
    • définir le code de retour (et le ramasser avec $?)
    • ‘echo’ certaines données (et ramasser avec MYVAR = $ (myfunction))

    Valeurs de retour des fonctions Bash

    Le problème avec les autres réponses est qu’ils utilisent soit un global, qui peut être écrasé lorsque plusieurs fonctions sont dans une chaîne d’appel, soit un écho qui signifie que votre fonction ne peut pas sortir des informations de diagnostic (vous oublierez que valeur de retour, contiendra plus d’informations que ce que votre interlocuteur attend, conduisant à un bug bizarre), ou eval qui est très lourd et pirate.

    La méthode appropriée consiste à placer les éléments de niveau supérieur dans une fonction et à utiliser une règle de scope dynamic de bash avec un élément local. Exemple:

     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 

    Cette sorties

     nothing hi bye 

    La scope dynamic signifie que ret_val pointe vers un object différent en fonction de l’appelant! Ceci est différent de la scope lexicale, qui est utilisée par la plupart des langages de programmation. C’est en fait une fonctionnalité documentée , facile à rater, et pas très bien expliquée, voici la documentation (l’accent est mis sur moi):

    Les variables locales à la fonction peuvent être déclarées avec le paramètre interne local. Ces variables ne sont visibles que par la fonction et les commandes qu’elle appelle .

    Pour quelqu’un avec un arrière-plan C / C ++ / Python / Java / C # / javascript, c’est probablement le plus gros obstacle: les fonctions de bash ne sont pas des fonctions, elles sont des commandes et se comportent comme suit: pipe in / out, ils peuvent retourner un code de sortie. Fondamentalement, il n’y a pas de différence entre définir une commande dans un script et créer un exécutable pouvant être appelé à partir de la commande.

    Donc, au lieu d’écrire votre script comme ceci:

     top-level code bunch of functions more top-level code 

    écris-le comme ceci:

     # define your main, containing all top-level code main() bunch of functions # call main main 

    où main () déclare ret_val comme local et toutes les autres fonctions renvoient des valeurs via ret_val.

    Voir aussi https://unix.stackexchange.com/questions/282557/scope-of-local-variables-in-shell-functions .

    Git Bash sous Windows en utilisant des tableaux pour plusieurs valeurs de retour

    BASH CODE:

     #!/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:" 

    PRODUCTION ATTENDUE:

     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: