Renvoyer une valeur à partir d'une fonction bash

10

J'ai une fonction qui renvoie 1 si le nombre est un nombre à dix chiffres valide:

valNum()
{
    flag=1
    if [[ $1 != [1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] ]]; then
        echo "Invalid Number"
        flag=0
    fi
    return $flag
}

Il est appelé par:

if [[ $(valNum $num) -eq 1 ]]; then
      #do something
fi

La fonction fonctionne correctement si le numéro est valide mais affiche une erreur de syntaxe si vous entrez un numéro non valide.

user2179293
la source

Réponses:

14

La réponse de @ choroba est correcte, mais cet exemple pourrait être plus clair:

valNum $num
valNumResult=$? # '$?' is the return value of the previous command
if [[ $valNumResult -eq 1 ]]
then
  : # do something
fi

Cet exemple est un peu plus long (définir $valNumResultpuis interroger cette valeur), mais décrit plus explicitement ce qui se passe: cela valNum()renvoie une valeur, et cette valeur peut être interrogée et testée.

PS Veuillez vous faire une faveur et retourner 0pour trueet non nul pour false. De cette façon, vous pouvez utiliser la valeur de retour pour indiquer «pourquoi nous avons échoué» dans le cas d'échec.


la source
8

Les fonctions de bash ne peuvent renvoyer que des codes de sortie. La substitution de commande, à l'inverse, est utilisée pour obtenir la sortie standard d'une commande ou d'une fonction. Par conséquent, pour vérifier l'indicateur renvoyé, vous n'avez pas besoin de la substitution:

if valNum "$num" ; then
    # ...
fi

Mais, pour que cela fonctionne, vous devez retourner 0 si le nombre est valide et 1 s'il ne l'est pas (le code de sortie 0 signifie aucune erreur).

choroba
la source
Je ne comprends pas. Dans l'exemple 24.7 de tldp.org/LDP/abs/html/complexfunct.html, la fonction renvoie la valeur maximale et non le code de sortie. Bien que votre suggestion fonctionne, mais je ne peux pas comprendre pourquoi elle fonctionne
user2179293
1
puisque votre test consiste à savoir si l'entrée est un entier valide à 10 chiffres ou non, c'est-à-dire vrai ou faux, la fonction renvoie soit 0 soit 1. L'exemple de choroba fonctionne car if valnum "$num"est équivalent à if valnum "$num" = 0ie "si c'est vrai". La règle de base dans les scripts sh est que 0 = vrai / succès, non nul = faux / erreur.
cas
2
BTW, que "Advanced Bash-Scripting Guide" n'est pas un très bon guide - il se trompe sur beaucoup de choses et encourage certaines mauvaises pratiques de script. la FAQ Bash sur mywiki.wooledge.org/BashFAQ est une bien meilleure ressource.
cas
votre fonction échoue car elle fait écho à la chaîne "Numéro invalide", et vous effectuez ensuite une comparaison numérique entre cette chaîne et le numéro 1 avecif [[ $(valNum $num) -eq 1 ]]
cas
5

Vous ne pouvez pas retourner un résultat arbitraire à partir d'une fonction shell. Vous ne pouvez renvoyer qu'un code d'état qui est un entier compris entre 0 et 255. (Bien que vous puissiez passer une valeur plus grande à return, il est tronqué modulo 256.) La valeur doit être 0 pour indiquer le succès et une valeur différente pour indiquer l'échec; par convention, vous devez vous en tenir aux codes d'erreur entre 1 et 125, car les valeurs plus élevées ont une signification spéciale (mauvaise commande externe pour 126 et 127, tuée par un signal pour les valeurs plus élevées).

Étant donné que vous renvoyez un résultat oui ou non ici, un code d'état est approprié. Puisque flagsemble indiquer un succès ou un échec, vous devez utiliser les valeurs conventionnelles de 0 pour le succès et 1 pour l'échec (l'opposé de ce que vous avez écrit). Vous pouvez ensuite utiliser votre fonction directement dans une instruction if.

valNum ()
{
  local flag=0
  if [[ $1 != [1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] ]]; then
    echo 1>&2 "Invalid Number"
    flag=1
  fi
  return $flag
}
if valNum "$num"; then
  #do something
fi

Si vous devez faire la distinction entre les codes de panne, appelez directement la fonction. Immédiatement après son retour, le code d'échec est disponible dans $?. Vous pouvez ensuite le vérifier avec une déclaration de cas:

valNum "$num"
case $? in 

Si vous devez utiliser le code d'état ultérieurement, enregistrez-le dans une autre variable avant qu'il ne $?soit remplacé par la commande suivante.

valNum "$num"
valNum_status=$?

Ce que vous avez écrit n'a pas fonctionné car la substitution de commande $(…)s'étend à la sortie de la fonction, qui dans votre code est soit le message d'erreur, soit vide, jamais 1.

Si vous avez besoin de transmettre plus d'informations qu'un code d'état ne permet de sortir d'un shell, vous avez deux possibilités:

  • Imprimez du texte sur la sortie standard et appelez la fonction dans une substitution de commande: $(valNum "$num")
  • Attribuez à une ou plusieurs variables à l'intérieur de la fonction et lisez ces variables ultérieurement.
Gilles 'SO- arrête d'être méchant'
la source
2

J'ai moi-même eu des résultats contradictoires dans ce domaine. Voici les résultats de mes expériences empiriques. Tout d'abord, une « théorie » sur les commandes bash ou * nix:

  • SUCCÈS == 0 ... à savoir. pas de code d'état d'erreur)
  • FAIL! = 0 ...... un code d'état

Exemple:

if  ls -lt /nonexistantdir
then 
    echo "found"
else
    echo "FAIL"
fi
#
echo
ls -lt /nonexistantdir; echo "status = $?"
echo "status = $?"

Production:

ls: cannot access '/nonexistantdir': No such file or directory
FAIL... 

ls: cannot access '/nonexistantdir': No such file or directory
status = 2

Comme indiqué, la lscommande renvoie le code d'état = 2. Lorsque vous essayez un répertoire valide, l'état est zéro ( 0 ). Pas le même que presque toutes les autres langues.

règle # 1 - Faire ...

  • VRAI == 0
  • FAUX! = 0

Nous devons nous rappeler que nous testons les codes d'erreur dans une ifinstruction Bash . J'ai mis en place des constantes, ou vous pouvez utiliser un shell trueou des falsecommandes.

TRUE=0
FALSE=1

#  valid number function
#
valNum()
{
    flag=$TRUE

    if [[ $1 != [1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] ]]; then
        echo "Invalid Number"
        flag=$FALSE
    fi
    return $flag
}

#    later on ...
#
if validNum Abc 
then
    echo "Lucky number"
else
    echo "Not lucky."
fi

et sortie:

Invalid Number
Not lucky.

Cependant, je vous suggère de donner tout @ vote « up-vote » parce que sa réponse est la bonne. Je voulais juste avoir le côté simpliste sur ePaper.

Juste une autre chose, la testcommande. Cela ressemble à ceci:

[[ some-expression ]]; 

La plupart du temps. Et par exemple:

$ test 1
$ echo "result = $?"
result = 0
$ test 0
$ echo "result = $?"
result = 0

Zéro (0) étant vrai . Pourquoi? Eh bien, la page de manuel indique qu'un seul argument est « vrai » lorsqu'il n'est PAS NUL.

références:

volonté
la source