Capturer le code de sortie de la commande exit

10

J'ai ceci dans un script bash:

exit 3;

exit_code="$?"

if [[ "$exit_code" != "0" ]]; then
    echo -e "${r2g_magenta}Your r2g process is exiting with code $exit_code.${r2g_no_color}";
    exit "$exit_code";
fi

Il semble qu'il sortira juste après la commande exit, ce qui est logique. Je me demandais s'il y avait une commande simple qui peut fournir un code de sortie sans sortir tout de suite?

J'allais deviner:

exec exit 3

mais il donne un message d'erreur: exec: exit: not found. Que puis-je faire? :)

G-Man dit «Réintègre Monica»
la source
1
Ouais ce exec exit 3n'est pas bueno, je reçois"exec: exit: not found"
7
Je ne comprends pas la question. Pourquoi ne pas définir exit_code=3et supprimer exit 3complètement la ligne?
wjandrea
@wjandrea est plus une question conceptuelle que pratique
2
Cela n'a toujours aucun sens pour moi. Pourquoi y aurait-il un code de sortie si vous ne quittez pas réellement?
Barmar
1
@Barmar chaque processus a un code de sortie. La plupart des gens qui essaient de répondre à la question interprètent la question comme signifiant "par quoi puis-je remplacer la" sortie 3 "dans le script afin qu'elle définit la $?variable mais ne quitte pas ce script"?
icarus

Réponses:

32

Si vous avez un script qui exécute un programme et examine l'état de sortie du programme (avec  $?), et que vous souhaitez tester ce script en faisant quelque chose qui entraîne $?une valeur connue (par exemple,  3), faites simplement

(exit 3)

Les parenthèses créent un sous-shell. Ensuite, la exitcommande provoque la fermeture de ce sous-shell avec l'état de sortie spécifié.

G-Man dit «Réintègre Monica»
la source
En outre, à des fins de débogage, il serait tout aussi simple de définir exit_code="3"pour les tests
Centimane
1
Oui, wjandrea l'a souligné hier.
G-Man dit `` Réintègre Monica ''
12

exitest un bash intégré, donc vous ne pouvez pas exec. Par manuel de bash :

L'état de sortie de Bash est l'état de sortie de la dernière commande exécutée dans le script. Si aucune commande n'est exécutée, l'état de sortie est 0.

En rassemblant tout cela, je dirais que votre seule option est de stocker l'état de sortie souhaité dans une variable, puis le exit $MY_EXIT_STATUScas échéant.

solarshado
la source
hmmm que pensez-vous de l'idée de @ G-man?
2
J'ai peut-être mal compris ce que vous essayez d'accomplir. Si vous essayez simplement de définir $?(même si je ne sais pas vraiment pourquoi vous le feriez), cela semble être une réponse solide. Si vous voulez juste le mettre à une valeur sans succès, falseest une autre option.
solarshado
10

Vous pouvez écrire une fonction qui retourne le statut donné en argument, ou 255si aucun n'est donné. (Je l'appelle retcar il "renvoie" sa valeur.)

ret() { return "${1:-255}"; }

et utilisez retà la place de votre appel à exit. Cela évite l'inefficacité de la création du sous-shell dans la réponse actuellement acceptée.

Quelques mesures.

time bash -c 'for i in {1..10000} ; do (exit 3) ; done ; echo $?'

sur ma machine prend environ 3,5 secondes.

 time bash -c 'ret(){ return $1 ; } ; for i in {1..10000} ; do ret 3 ; done ; echo $?'

sur ma machine prend environ 0,051 seconde, 70 fois plus vite. Mettre dans la gestion par défaut le laisse encore 60 fois plus rapide. De toute évidence, la boucle a des frais généraux. Si je change le corps de la boucle pour qu'il soit juste :ou truealors le temps est divisé par deux à 0,025, une boucle complètement vide est une syntaxe invalide. L'ajout ;:à la boucle montre que cette commande minimale prend 0,007 seconde, donc la surcharge de la boucle est d'environ 0,018. La soustraction de cette surcharge des deux tests montre que la retsolution est plus de 100 fois plus rapide.

C'est évidemment une mesure synthétique, mais les choses s'additionnent. Si vous faites tout 100 fois plus lentement que nécessaire, vous vous retrouvez avec des systèmes lents. 0,0

icare
la source
2
@iBug L'espace supplémentaire n'est pas nécessaire.
icarus
Bon point sur l'inefficacité de la création du sous-shell. J'ai lu que certains shells pouvaient être assez intelligents pour optimiser le fork dans des cas comme celui-ci, mais ce bash n'en fait pas partie.
G-Man dit `` Réintègre Monica ''
3

À propos exec exit 3... il essaierait d'exécuter une commande externe appelée exit, mais il n'y en a pas, donc vous obtenez l'erreur. Il doit s'agir d'une commande externe au lieu d'une commande intégrée au shell, car exec remplace complètement le shell. Ce qui signifie également que même si vous aviez une commande externe appelée exit, exec exit 3ne reviendrait pas pour continuer votre script shell, car le shell ne serait plus là .

ilkkachu
la source
1
Je suppose que vous pourriez le faire exec bash -c "exit 3", mais pour le moment, je ne vois aucune raison de le faire par opposition à juste exit 3.
David Z
1
@DavidZ, dans tous les cas, exec'ing ou tout simplement exit' arrêtera le script, ce qui ne semblait pas être ce que la question voulait.
ilkkachu
3

Vous pouvez le faire avec Awk:

awk 'BEGIN{exit 9}'

Ou Sed:

sed Q9 /proc/stat
Steven Penny
la source
... ou avec une coquille:sh -c 'exit 9'
ilkkachu
1
@ilkkachu si vous allez faire cela, vous feriez aussi bien de le faire (exit 9)dans la réponse acceptée
Steven Penny