Valeur de retour dans une fonction de 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 j'exécute fun2
, il n'imprime pas"34". Pourquoi est-ce le cas?
9 réponses
bien que bash ait une déclaration return
, la seule chose que vous pouvez spécifier avec elle est le propre statut exit
de la fonction (une valeur entre 0
et 255
, 0 signifiant "succès"). Donc return
n'est pas ce que vous voulez.
vous pourriez vouloir convertir votre déclaration return
en une déclaration echo
- de cette façon votre sortie de fonction pourrait être capturée en utilisant des bretelles $()
, 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 simplement retourner un entier 0-255) est $?
.
function fun1(){
return 34
}
function fun2(){
fun1
local res=$?
echo $res
}
aussi, notez que vous pouvez utiliser la valeur de retour pour utiliser la logique booléenne comme fun1 || fun2
ne lancera fun2
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 vers stdout. $?
contient le code de résultat de la dernière commande.
fun1 (){
return 34
}
fun2 (){
fun1
local res=$?
echo $res
}
dans Bash ne sont pas des fonctions comme dans les autres langues; ce sont en fait des commandes. Ainsi les fonctions sont utilisées comme si elles étaient des binaires ou des scripts récupérés à partir de votre chemin. Du point de vue de la logique de votre programme, il ne devrait y avoir aucune différence.
Les commandes Shell sont connectées par des pipes (alias streams), et non par des types de données fondamentales ou définies par l'utilisateur, comme dans les langages de programmation" réels". Il n'y a pas de telle chose comme une valeur de retour pour une commande, peut-être surtout parce qu'il n'y a pas de vrai 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 écrits au vent.
Lorsqu'une commande veut obtenir l'entrée de la lecture à partir de ses flux d'entrée, ou de la liste d'arguments. Dans les deux cas, les chaînes de texte à analyser.
Lorsqu'une commande veut retourner quelque chose, elle doit echo
le renvoyer à son flux de sortie. Un autre oftenly practiced way est de stocker la valeur de retour dans des variables globales dédiées. L'écriture dans le flux de sortie est plus claire et plus flexible, parce qu'elle peut prendre aussi des données binaires. Par exemple, vous pouvez retourner un BLOB facilement:
encrypt() {
gpg -c -o- # 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 aussi utiliser la substitution de commande $()
pour capturer la sortie.
parallèlement, la fonction" retournerait "le code de sortie de gpg
(GnuPG). Pensez à la code de sortie comme bonus que d'autres langues n'ont pas, ou, selon votre tempérament, comme un "Schmutzeffekt" de fonctions shell. Ce statut est, par convention, 0 sur le succès ou un entier dans la gamme 1-255 pour autre chose. Pour être clair: return
(comme exit
) ne peut prendre une valeur que de 0 à 255, et les valeurs autres que 0 ne sont pas nécessairement des erreurs, comme on le dit souvent.
quand vous ne fournissez pas une valeur explicite avec return
le statut est pris à partir de la dernière commande dans un Bash déclaration/fonction/commande et ainsi de suite. Donc il y a toujours un statut, et return
est juste un moyen facile de fournir.
l'instruction return
définit le code de sortie de la fonction, à peu près comme exit
le fera pour le script entier.
le code de sortie de la dernière commande est toujours disponible dans la 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 l'exécution dans un script où 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 cela, parce que je peux alors inclure des déclarations 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 excellents billets des autres, voici un article résumant ces techniques:
- définir une variable globale
- définit une variable globale, dont vous avez passé le nom à la fonction
- définir le code de retour (et le ramasser avec $?)
- 'echo' certaines données (et le ramasser avec MYVAR=$(mafonction) )
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, ou un écho qui signifie que votre fonction ne peut pas produire des informations de diagnostic (vous oublierez votre fonction fait cela et le "résultat", c'est-à-dire la valeur de retour, contiendra plus d'informations que votre interlocuteur s'attend, conduisant à bug bizarre), ou eval qui est très lourd et hacky.
la bonne façon de faire ceci est de mettre la substance de haut niveau dans une fonction et d'utiliser un local avec la règle dynamique de bash. 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
Ce sorties
nothing
hi
bye
définition dynamique signifie que ret_val pointe vers un objet différent selon l'appelant! Ceci est différent de la portée lexicale, qui est ce que la plupart des langages de programmation utilisent. C'est en fait une fonctionnalité documentée , facile à manquer, et pas très bien expliqué, voici les docs pour elle (l'emphase est mienne):
les Variables locales à la fonction peuvent être déclarées avec le local builtin. Ces variables ne sont visibles que pour la fonction et le commande il invoque .
pour quelqu'un avec un arrière-plan C/C++/Python/Java/C#/javascript, c'est probablement le plus grand obstacle: les fonctions en bash ne sont pas des fonctions, ce sont des commandes, et se comportent comme telles: elles peuvent sortir en stdout/stderr, elles peut entrer/sortir, 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 qui peut ê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
écrivez comme ceci:
# define your main, containing all top-level code
main()
bunch of functions
# call main
main
où main() déclare ret_val 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 sur Windows à l'aide de tableaux de multiple valeurs de retour
CODE BASH:
#!/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
## and some sensible names:
local out_dex_1="" ##output index
local out_dex_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:"
RÉSULTATS ESCOMPTÉS:
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: