J'ai eu des problèmes étranges avec bash ces derniers temps. En essayant de simplifier mon script, j'ai trouvé ce petit morceau de code:
$ o(){ echo | while read -r; do return 0; done; echo $?;}; o
0
$ o(){ echo | while read -r; do return 1; done; echo $?;}; o
1
return
aurait dû quitter la fonction sans imprimer $?
, n'est-ce pas? Eh bien, j'ai vérifié si je pouvais revenir d'un tuyau seul:
$ echo | while read -r; do return 1; done
bash: return: can only `return' from a function or sourced script
La même chose se produit sans while
boucle:
$ foo(){ : | return 1; echo "This should not be printed.";}
$ foo
This should not be printed.
Y a-t-il quelque chose qui me manque ici? Une recherche Google n'a rien apporté à ce sujet! Ma version bash est la version 4.2.37 (1) sur Debian Wheezy.
bash
shell-script
pipe
subshell
Teresa e Junior
la source
la source
while
n'est pas nécessaire pour la reproduction? Cela détourne l'attention du sujet.while
boucle est une utilisation très courante pour un tuyau avecreturn
. Le deuxième exemple est plus direct, mais c'est quelque chose que je ne pense pas que quiconque utiliserait jamais ...Réponses:
En relation: /programming//a/7804208/4937930
Ce n'est pas un bug que vous ne pouvez pas quitter un script ou retourner d'une fonction par
exit
oureturn
en sous-shell. Ils sont exécutés dans un autre processus et n'affectent pas le processus principal.En plus de cela, je suppose que vous voyez des comportements non documentés de bash sur (probablement) des spécifications non définies. Dans une fonction, aucune erreur n'est affirmée
return
au niveau supérieur des commandes de sous-shell et elle se comporte simplement commeexit
.À mon humble avis, c'est un bogue bash pour le comportement incohérent de
return
selon que l'instruction principale est dans une fonction ou non.Production:
la source
return
cela ne fonctionne pas à partir d'une séquence de commandes de niveau supérieur dans un sous-shell, et en particulier ne quitte pas le sous-shell, est ce que les documents existants m'ont déjà fait attendre. L'OP pourrait utiliserexit 1 || return 1
où ils essaient d'utiliserreturn
, et devrait ensuite obtenir le comportement attendu. EDIT: La réponse de @ herbert indique que le niveau supérieurreturn
dans le sous-shell fonctionne commeexit
(mais uniquement à partir du sous-shell).return
dans une simple séquence de sous-shell devrait être affirmé comme une erreur d'exécution dans tous les cas , mais en réalité ce n'est pas quand cela se produit dans une fonction. Ce problème a également été discuté dans gnu.bash.bug , mais il n'y a pas de conclusion.return
déclaration a une fonction et est donc légale. Le comportement résultant n'est cependant pas spécifié.Ce n'est pas un bug
bash
mais son comportement documenté :L'
return
instruction est valide étant à l'intérieur d'une définition de fonction mais étant également dans un sous-shell, elle n'affecte pas son shell parent donc l'instruction suivante,,echo
est exécutée malgré tout. Il s'agit néanmoins d'une construction shell non portable car le standard POSIX permet aux commandes composant un pipeline d'être exécutées soit dans un sous-shell (par défaut) soit dans le top (une extension autorisée).Avec un peu de chance, vous pouvez dire
bash
de vous comporter comme vous le souhaitez avec quelques options:la source
return
ne quittera pas la fonction, cela n'aurait-il pas plus de sens si le shell venait d'être imprimébash: return: can only `return' from a function or sourced script
, au lieu de donner à l'utilisateur un faux sens que la fonction aurait pu être retournée?return
depuis un sous-shell. Après tout, il sait que c'est dans un sous-shell, comme en témoigne la$BASH_SUBSHELL
variable. Le plus gros problème est que cela pourrait conduire à des faux positifs; un utilisateur qui comprend le fonctionnement des sous-coquilles pourrait avoir écrit des scripts qui utilisentreturn
à la place deexit
mettre fin à une sous-coquille. (Et, bien sûr, il existe des cas valides où l'on peut vouloir définir des variables ou faire uncd
en sous-shell.)return
revient du sous-shell au lieu d'échouer, car il se trouve dans une fonction réelle. Le problème est le suivanthelp return
: à laCauses a function or sourced script to exit with the return value specified by N.
lecture de la documentation, tout utilisateur s'attendrait à ce qu'il échoue ou affiche au moins un avertissement, mais ne se comporte jamais commeexit
.return
dans un sous-shell dans une fonction pour revenir de la fonction (dans le processus shell principal) ne comprend pas très bien les sous-shell. Inversement, je m'attendrais à ce qu'un lecteur qui comprend les sous-coquilles s'attende à cereturn
qu'une sous-coquille dans une fonction termine la sous-coquille, tout comme leexit
ferait.Selon la documentation POSIX, l' utilisation en
return
dehors de la fonction ou du script source n'est pas spécifiée . Cela dépend donc de votre shell à gérer.Le shell SystemV signalera une erreur, tandis que dans
ksh
, enreturn
dehors de la fonction ou du script source se comportera commeexit
. La plupart des autres shells POSIX et l' os de schily se comportent également comme ça:ksh
etzsh
n'a pas été généré car la dernière partie du tuyau dans ces shells a été exécutée dans le shell actuel au lieu de sous-shell. L'instruction return a affecté l'environnement shell actuel qui a appelé la fonction, provoquant le retour immédiat de la fonction sans rien imprimer.Dans une session interactive,
bash
signalez uniquement l'erreur mais n'avez pas terminé le shell,schily's osh
signalé l'erreur et terminé le shell:(
zsh
dans la session interactive et la sortie est le terminal ne s'est pas terminébash
,yash
et aschily's osh
signalé l'erreur mais n'a pas terminé le shell)la source
return
est utilisé à l' intérieur d' une fonction ici.return
été utilisé à l' intérieur de la fonction sous-shell à l' intérieur , sauf et .ksh
zsh
Je pense que vous avez obtenu le comportement attendu, en bash, chaque commande dans un pipeline est exécutée en sous-shell. Vous pouvez vous convaincre en essayant de modifier une variable globale de votre fonction:
Soit dit en passant, le retour fonctionne mais il revient du sous-shell. Encore une fois, vous pouvez vérifier que:
Sortira les éléments suivants:
Donc, l'instruction de retour a correctement quitté le sous-shell
.
la source
foo(){ : | return 1 || return 2; echo$?; echo "This should not be printed.";}; foo; echo $?
et vous obtiendrez un résultat de2
. Mais pour plus de clarté , je ferais lereturn 1
soitexit 1
.La réponse plus générale est que bash et certains autres shells placent normalement tous les éléments d'un pipeline dans des processus séparés. Ceci est raisonnable lorsque la ligne de commande est
puisque les programmes sont normalement exécutés dans des processus séparés de toute façon (sauf si vous dites ). Mais cela peut surprendre
exec program
où certaines ou toutes les commandes sont des commandes intégrées. Des exemples triviaux comprennent:
Un exemple un peu plus réaliste est
où l'ensemble
while
...do
... ladone
boucle est mis dans un sous - processus, et ainsi ses modificationst
ne sont pas visibles sur la coque principale après la fin de la boucle. Et c'est exactement ce que vous faites: canaliser dans unewhile
boucle, faire fonctionner la boucle en tant que sous-shell, puis essayer de revenir du sous-shell.la source