Différence entre le retour et la sortie dans les fonctions Bash


429

Quelle est la différence entre l' instruction returnet exitdans les fonctions Bash en ce qui concerne les codes de sortie?


55
Protip: saisissez help <command>votre shell pour obtenir des informations sur ce que fera un shell intégré. Dans votre cas help returnethelp exit
SiegeX

Réponses:


318

À partir man bashde return [n];

Force une fonction à arrêter son exécution et à renvoyer la valeur spécifiée par n à son appelant. Si n est omis, l'état de retour est celui de la dernière commande exécutée dans le corps de la fonction.

... le exit [n]:

Faire sortir le shell avec un état de n. Si n est omis, l'état de sortie est celui de la dernière commande exécutée. Une interruption sur EXIT est exécutée avant la fin du shell.

ÉDITER:

Selon votre modification de la question, concernant les codes de sortie, returnn'a rien à voir avec les codes de sortie. Les codes de sortie sont destinés aux applications / scripts , pas aux fonctions. À cet égard, le seul mot-clé qui définit le code de sortie du script (celui qui peut être intercepté par le programme appelant à l'aide de la $?variable shell) est exit.

EDIT 2:

Ma dernière déclaration faisant référence exitsuscite quelques commentaires. Il a été fait pour différencier returnet exitpour la compréhension de l'OP, et en fait, à tout moment donné d'un programme / script shell, exitest le seul moyen de terminer le script avec un code de sortie pour le processus appelant.

Chaque commande exécutée dans le shell produit un "code de sortie" local: elle définit la $?variable sur ce code, et peut être utilisée avec if, &&et d'autres opérateurs pour exécuter conditionnellement d'autres commandes.

Ces codes de sortie (et la valeur de la $?variable) sont réinitialisés à chaque exécution de commande.

Par ailleurs, le code de sortie de la dernière commande exécutée par le script est utilisé comme code de sortie du script lui-même tel qu'il est vu par le processus appelant.

Enfin, les fonctions, lorsqu'elles sont appelées, agissent comme des commandes shell par rapport aux codes de sortie. Le code de sortie de la fonction ( dans la fonction) est défini à l'aide de return. Ainsi, lorsqu'une fonction return 0est exécutée, l'exécution de la fonction se termine, donnant un code de sortie de 0.


10
Pas exactement. Il retourne toujours une valeur du shell courant. Peu importe que vous soyez dans une fonction ou non.
Diego Sevilla

10
Commentaire sur votre edit: je peut être source de confusion des valeurs de retour et les codes de sortie, mais les func(){ return 50; };func;echo $?échos 50. Ainsi , la $?variable shell ne semble pas se limiter à exit.
lecodesportif

8
" $?S'étend au statut de sortie du dernier pipeline de premier plan exécuté." Cette sortie peut être à partir du shell sous la forme d'un appel à exit(ou de la fin du script) ou sous la forme d'un appel à l' returnintérieur d'une fonction.
SiegeX

11
@lecodesportif: Le $? processus / script en cours est limité soit au exitrésultat de la dernière commande exécutée par ce script. Donc, si votre dernière ligne de script est l'appel à cette fonction, et que cette fonction renvoie 50, oui, le $?que vous produisez au processus qui vous a appelé est 50. Cependant, cela n'a pas à voir avec le return, car c'est limité au script actuel. Il n'est renvoyé que si cet appel de fonction est la dernière phrase du script. exit, cependant, terminez toujours le script et renvoyez cette valeur quant $? au processus appelant .
Diego Sevilla,

11
-1 pour m'avoir confondu avec la ligne " returnn'a rien à voir avec les codes de sortie". L'expérimentation me dit qu'il n'y a pas de différence fonctionnelle entre le code retour d'une fonction et le code de sortie d'un script.
Jack

296

returnentraînera la sortie de la fonction en cours, tandis exitque le script se terminera au point où il est appelé. Voici un exemple de programme pour expliquer cela:

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"

Production

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()

17
Bel exemple. Vous pouvez également afficher la valeur de sortie de 1 pouce $?.
Diego Sevilla

48
Notez que cette fonction n'imprimera PAS "Nous sommes toujours là" si vous ajoutez "set -e" avant l'appel à "retfunc".
Michael

4
Cependant, echo fnord | while read x; do exitfunc; done; echo "still here"imprimera "toujours ici". Il semble que seul le whilesous-shell soit quitté dans ce scénario.
tripleee

Une solution de contournement approximative est, done || exit $?mais c'est moche et pas exactement équivalent.
tripleee

2
+1 Il pourrait être utile d'ajouter: `` `` returnfera sortir la fonction actuelle ou le script d'origine ''.
Isaac

56

Je ne pense pas que quiconque ait vraiment répondu pleinement à la question, car il ne décrit pas comment les deux sont utilisés. OK, je pense que nous savons que exit tue le script, où qu'il soit appelé, et vous pouvez également lui attribuer un statut tel que exit ou exit 0 ou exit 7 et ainsi de suite. Cela peut être utilisé pour déterminer comment le script a été forcé de s'arrêter s'il était appelé par un autre script, etc. Assez à la sortie.

return lors de l'appel renvoie la valeur spécifiée pour indiquer le comportement de la fonction, généralement 1 ou 0. Par exemple:

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }

vérifier comme ça:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi

ou comme ça:

    isdirectory || echo "not a directory"

Dans cet exemple, le test peut être utilisé pour indiquer si le répertoire a été trouvé. notez que rien après le retour ne sera exécuté dans la fonction. 0 est vrai mais faux est 1 dans le shell, différent des autres langages prog.

Pour plus d'informations sur les fonctions: http://www.linuxjournal.com/content/return-values-bash-functions

REMARQUE: La fonction isdirectory est uniquement à des fins pédagogiques. Cela ne devrait pas être la façon dont vous effectuez une telle option dans un vrai script.


3
Ou utilisez simplement test -d $1pour obtenir le même résultat. Jamais if <check> return else return. <check>seul fera la même chose dans toutes les langues que je connais au moins.
erikbwork

4
Pour être encore plus explicite sur ce que dit erik: isdirectory() { [ -d "$1" ]; }se comportera exactement de la même manière que ce que vous avez ici: la valeur de retour par défaut d'une fonction shell, que ce soit en atteignant la fin de son code ou par un returnsans argument, est celle du commande la plus récente.
Charles Duffy

11
Les autres commentateurs ici critiquent le style de l'exemple de Mike Q, alors qu'il parle vraiment du comportement de la returndéclaration. Il est vrai que son exemple est simpliste et ne doit pas être utilisé en production. Mais c'est simple, donc il accomplit très bien sa tâche. Rien de mal à cela.
Mike S

Merci Mike S, oui je suis d'accord pour dire que l'exemple le plus simple explique le mieux sortie vs retour. Les autres commentaires sont certainement valables et devraient être pris en compte pour les codeurs bash plus avancés ;-)
Mike Q

1
Certains pourraient dire que ce n'est pas exactement lié à la question, mais il est lié au problème que j'ai rencontré et m'a répondu qui m'a amené à trouver cette question. :-)
Jesse Steele

33

N'oubliez pas que les fonctions sont internes à un script et reviennent normalement d'où elles ont été appelées en utilisant l'instruction return. L'appel d'un script externe est une tout autre affaire, et les scripts se terminent généralement par une instruction exit.

La différence "entre l'instruction return et exit dans les fonctions BASH par rapport aux codes de sortie" est très faible. Les deux renvoient un statut, pas des valeurs en soi. Un état de zéro indique la réussite, tandis que tout autre état (1 à 255) indique un échec. L'instruction return retournera au script d'où elle a été appelée, tandis que l'instruction exit terminera l'intégralité du script d'où qu'il se trouve.

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).

Si votre fonction se termine simplement sans instruction de retour, l'état de la dernière commande exécutée est renvoyé en tant que code d'état (et sera placé dans $?).

N'oubliez pas, retour et sortie donnent un code d'état de 0 à 255, disponible en $?. Vous ne pouvez pas insérer quoi que ce soit d'autre dans un code d'état (par exemple, renvoyer "cat"); ça ne marchera pas. Mais, un script peut renvoyer 255 raisons différentes d'échec en utilisant des codes d'état.

Vous pouvez définir des variables contenues dans le script appelant, ou faire écho aux résultats dans la fonction et utiliser la substitution de commandes dans le script appelant; mais le but du retour et de la sortie est de transmettre des codes d'état, pas des valeurs ou des résultats de calcul comme on pourrait s'y attendre dans un langage de programmation comme C.


25

Parfois, vous exécutez un script à l'aide de .ou source.

. a.sh

Si vous incluez un exitdans le a.sh, il ne mettra pas seulement fin au script, mais mettra fin à votre session shell.

Si vous incluez un returndans le a.sh, il arrête simplement le traitement du script.


1
Mais lorsque je lance juste a.sh, j'obtiens une erreur return: can only 'return' from a function or sourced script, ce qui le rend inapproprié pour un script général.
Peter - Rétablir Monica

Au niveau supérieur dans un script, ni l'un ni l'autre ne convient dans des allsituations. Utiliser .ou sourceexécuter le script dans le shell actuel, plutôt que de générer un sous-shell. Le script doit savoir comment il doit être utilisé. Malheur à l'utilisateur qui le fait en face. Personnellement, je recommande de lire les scripts avant de les exécuter la première fois.
Jesse Chisholm

3
Une astuce géniale que j'ai rencontrée consiste à utiliser une trapfonction pour ERR EXIT, puis à enregistrer le code de sortie d'une commande ayant échoué errCode=$?, puis à quitter le script (source ou non) avec return $errCode || exit $errCodeles ||moyens "si je ne peux pas revenir parce que je n'étais pas source , quittez simplement à la place ".
dragon788

6

En termes simples (principalement pour les débutants dans le codage), nous pouvons dire,

`return` : exits the function,
`exit()` : exits the program(called as process while running)

Aussi, si vous avez observé, c'est très basique mais ...,

`return` : is the keyword
`exit()` : is the function

1
Dans un script bash, exitn'est ni plus ni moins une fonction que return. Ce sont des commandes intégrées. Ce ne sont même pas des mots réservés.
Peter - Rétablir Monica

6
  • exitmettre fin au processus en cours ; avec ou sans code de sortie, considérez ceci comme un système plus qu'une fonction de programme. Notez que lors de l'approvisionnement, exitle shell se terminera, cependant, lors de l'exécution ne sera que exitle script.

  • returndepuis une fonction, revenir à l'instruction après l'appel, avec ou sans code retour. returnest facultatif et implicite à la fin de la fonction. returnne peut être utilisé qu'à l'intérieur d'une fonction.

Je veux ajouter que tout en étant sourcé, il n'est pas facile de faire exitle script à partir d'une fonction sans tuer le shell. Je pense qu'un exemple vaut mieux sur un script 'test'

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"

faire ce qui suit:

user$ ./test
Whatever is not available
user$

test -et- le shell va se fermer.

user$ . ./test
Whatever is not available

seulement testse terminera et l'invite s'affichera.

La solution consiste à enfermer la procédure potentiellement dans (et)

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added

maintenant, dans les deux cas, seul testquittera.


L'ajout de (et )place ce bloc dans un sous-shell, annule effectivement la .commande (source) comme si vous aviez exécuté le script de test normalement, qui se trouve dans un sous-shell. Si le script n'est pas exécuté avec .ou sourcealors vous avez effectivement 2 sous-shells.
Jesse Chisholm

3

La question de l'OP: Quelle est la différence entre l'instruction return et exit dans les fonctions BASH par rapport aux codes de sortie?

Tout d'abord, quelques éclaircissements s'imposent:

  • Une instruction (return | exit) n'est pas requise pour terminer l'exécution d'une (fonction | shell). Une (fonction | shell) se terminera lorsqu'elle atteindra la fin de sa liste de codes, même sans instruction (return | exit).
  • Une instruction (return | exit) n'est pas requise pour renvoyer une valeur à partir d'une (fonction | shell) terminée. Chaque processus a une variable intégrée $? qui a toujours une valeur numérique. Il s'agit d'une variable spéciale qui ne peut pas être définie comme "? = 1", mais qui n'est définie que de manière spéciale (voir ci-dessous *). La valeur de $? après la dernière commande à exécuter dans la (appelée fonction | sous-shell) est la valeur qui est renvoyée à la (fonction appelant | shell parent). Cela est vrai que la dernière commande exécutée soit ("return [n]" | "exit [n]") ou plain ("return" ou autre chose qui se trouve être la dernière commande dans le code des fonctions appelées.

Dans la liste à puces ci-dessus, choisissez parmi "(x | y)" soit toujours le premier élément, soit toujours le deuxième élément pour obtenir des instructions sur les fonctions & return ou shells & exit respectivement.

Ce qui est clair, c'est qu'ils partagent tous deux une utilisation commune de la variable spéciale $? pour passer des valeurs vers le haut après leur fin.

* Maintenant, pour les façons spéciales que $? peut être mis en place:

  • Lorsqu'une fonction appelée se termine et revient à son appelant, alors $? dans l'appelant sera égal à la valeur finale de $? dans la fonction terminée.
  • Lorsqu'un shell parent attend implicitement ou explicitement un seul sous-shell et est libéré par la fin de ce sous-shell, alors $? dans le shell parent sera égal à la valeur finale de $? dans le sous-shell terminé.
  • Certaines fonctions intégrées peuvent modifier $? en fonction de leur résultat. Mais certains ne le font pas.
  • Les fonctions intégrées "return" et "exit", lorsqu'elles sont suivies d'un argument numérique à la fois $? avec l'argument et terminer l'exécution.

Il vaut la peine de noter que $? peut être assigné une valeur en appelant exit dans un sous-shell, comme ceci:

# (exit 259)
# echo $?
3  

4
Au cas où certains l'auraient manqué, exit 259échos comme 3parce que la valeur de sortie finale est un seul octet. 259 % 256 = 3
Jesse Chisholm

0

Tout d'abord, returnc'est un mot-clé et exitmon ami est une fonction.

Cela dit, voici une explication des plus simples.

return Il renvoie une valeur d'une fonction.

exit Il quitte ou abandonne le shell actuel.


Pas vraiment! Vous vous trompez logiquement. Quitter est une fonction tandis que returnest un mot-clé. Le retour est bien plus que des codes de sortie, c'est pourquoi la comparaison n'est pas équitable.
Ahmad Awais du

Je l'ai édité pour clarifier le point que j'essayais de faire valoir. Merci de m'avoir aidé à faire ça.
Ahmad Awais

4
Ni exitne returnsont « mots clés », ou, comme les appels manuels bash eux, « mots réservés ». Ni l'un ni l'autre n'est une "fonction" non plus, au sens d'une fonction bash. Les deux sont des commandes intégrées, dans le jargon bash. (Il existe une fonction de bibliothèque standard C appelée exit(), et le langage de programmation C a un mot réservé return, mais il ne faut pas les confondre avec les commandes bash, même si leur sémantique est curieusement similaire.)
Peter - Reinstate Monica
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.