Aussi disponible en : English · Español · Português · العربية
Les codes de sortie expliqués
Cherchez un code de sortie Unix et voyez toutes les lectures qu'il admet, et quel document appuie chacune d'elles.
Qu'est-ce qu'un code de sortie ?
Quand un programme se termine, il remet au système un unique nombre compris entre 0 et 255. Zéro signifie qu'il a réussi. Toute autre valeur signifie qu'il a échoué, et c'est à peu près tout ce qui est garanti. Le shell conserve ce nombre dans la variable qui s'écrit avec un point d'interrogation, les systèmes d'intégration continue l'affichent quand une étape échoue, et les moteurs de conteneurs le rapportent quand quelque chose s'arrête.
Presque tous les tableaux de codes de sortie du web présentent une seule liste plate — 0 succès, 1 erreur générale, 2 mauvais usage des primitives, 64 à 78 pour sysexits, 126, 127, 128 plus le numéro de signal — comme si une norme unique disait tout cela. À lire les documents réels, ces lignes viennent de quatre endroits différents, et l'une des plus citées ne vient de nulle part. Cette page décode un code et indique, pour chaque lecture, quel document la soutient.
La distinction n'est pas de la pédanterie. C'est la différence entre une règle qu'un autre programme respectera et une habitude simplement répandue dans le coin du monde où vous l'avez apprise.
Comment l'utiliser
- Saisissez le nombre. Celui qu'a affiché votre journal d'intégration continue, votre moteur de conteneurs ou votre shell. Les boutons couvrent ceux que l'on rencontre le plus souvent.
- Lisez toutes les lectures, pas seulement la première. Un même nombre peut être plusieurs choses à la fois : 64 est à la fois un code sysexits et un nombre quelconque qu'un programme a choisi pour ses propres raisons, et n'en montrer qu'une serait affirmer ce que les sources ne disent pas.
- Regardez qui le définit. Chaque lecture porte une étiquette : POSIX, manuel de Bash, sysexits.h, ou aucune norme. C'est cette étiquette qui mérite d'être retenue.
Quels nombres sont réellement spécifiés
POSIX, dans son chapitre sur le langage du shell, fixe très peu de choses : zéro pour le succès, 127 lorsqu'une commande est introuvable, et 126 lorsqu'elle est trouvée mais ne peut pas être exécutée. Ces trois-là valent partout. Pour un programme tué par un signal, il dit seulement que le code sera supérieur à 128 et identifiera le signal d'une manière définie par l'implémentation ; il ne dit pas 128 plus le numéro du signal.
Ce dernier point surprend, car 128 plus le numéro du signal est exactement ce qui se produit. Cela figure dans le manuel de Bash et non dans POSIX : bash indique que lorsqu'une commande se termine sur un signal fatal N, il utilise 128+N. Mesuré ici avec bash, dash et le shell du système, les trois ont concordé : un processus tué par SIGTERM a renvoyé 143, par SIGKILL 137, par SIGINT 130 et par SIGHUP 129. C'est fiable en pratique, et c'est la promesse d'un shell, pas celle de la norme.
Bash définit aussi le 2, mais bien plus étroitement que ne le laissent croire les tableaux : toutes ses primitives renvoient 2 pour signaler un usage incorrect, par exemple une option invalide ou un argument manquant. C'est un fait au sujet des primitives de bash. Ce n'est pas un conseil sur ce que votre script devrait renvoyer, et rien n'oblige un autre programme à s'y conformer.
Et puis il y a le 1, le code de sortie le plus tabulé d'internet, légendé partout erreur générale. Aucun document ne le définit. POSIX et le manuel de Bash disent uniquement qu'une valeur non nulle signale un échec. Sur les 256 valeurs possibles, un document dit quelque chose de 50 d'entre elles ; les 206 autres sont laissées entièrement au programme.
Deux choses que les tableaux racontent mal
La première est sysexits. Les codes de 64 à 78 sont présentés partout comme les codes de sortie normalisés, et ils n'ont jamais fait partie de POSIX. Ils viennent d'un en-tête C écrit pour sendmail, et cet en-tête est remarquablement franc sur lui-même : il dit que les valeurs n'existent que pour la compatibilité d'interface et sont obsolètes pour les logiciels de base de FreeBSD, qu'elles ont été écrites pour sendmail en particulier et — juste avant de les énumérer — que le sens des codes est approximativement le suivant. Un jeu de constantes dont l'auteur qualifie lui-même les significations d'approximatives est une convention raisonnable au sein d'un projet qui l'emploie déjà, et un mauvais pari si vous attendez du programme d'un inconnu qu'il la respecte.
La seconde est que 128 plus un numéro de signal n'identifie pas toujours un signal. Remonter du code au signal suppose de savoir quel signal porte ce numéro, et les numéros de signaux ne sont pas les mêmes partout. Sous Linux sur x86, le signal 10 est SIGUSR1 ; sur Alpha, SPARC et macOS, c'est SIGBUS. Le code 138 désigne donc un signal utilisateur sur une machine et une erreur de bus sur une autre, et aucun tableau imprimant un seul nom ne peut avoir raison dans les deux cas. Saisissez 138 ci-dessus et l'outil vous montre la division au lieu de trancher à votre place.
Il y a un piège plus petit dans l'autre sens. Le code tient sur huit bits, donc renvoyer davantage repart silencieusement à zéro : exit 256 arrive comme 0, ce qui transforme un échec en succès. Mesuré ici, exit 300 est revenu à 44 et exit 257 à 1. Les valeurs négatives sont pires qu'un simple débordement : bash a transformé -1 en 255, tandis que dash l'a refusé avec un message de nombre illégal et a renvoyé 2 — le même script signale donc deux échecs différents selon le shell qui l'exécute.
Pourquoi non nul ne veut pas dire cassé
La convention que chacun transporte veut que zéro aille bien et que tout le reste soit un problème. Les deux utilitaires les plus présents dans un tube la contredisent. grep renvoie 1 lorsqu'il n'a tout simplement rien trouvé, et réserve le 2 à une véritable erreur. diff renvoie 1 lorsque les fichiers diffèrent, ce qui est la réponse normale à la question posée, et réserve lui aussi le 2. cmp fait de même.
C'est la raison pratique pour laquelle l'avertissement au bas de chaque résultat de cette page compte. Un script sous set -e s'arrêtera sur un grep qui n'a rien trouvé, car le shell ne distingue pas une réponse négative d'un échec : les deux valent 1. Savoir lesquels de vos outils emploient le 1 comme réponse plutôt que comme erreur est plus utile que n'importe quel tableau de codes normalisés, parce que c'est le cas qui mord vraiment.
Si vous choisissez des codes pour votre propre programme : zéro pour le succès, non nul pour l'échec, et documentez ce que signifie chaque nombre. C'est là tout le contrat portable. Si vous voulez davantage de structure, choisissez un schéma et écrivez-le, car celui qui lira votre code de sortie n'a aucun moyen de le consulter.
Pourquoi est-ce gratuit ?
Ce n'est qu'une table de correspondance et un peu d'arithmétique, exécutées dans votre navigateur. Il n'y a rien à faire tourner sur un serveur, donc rien à facturer et aucun compte à créer.
Rien de ce que vous saisissez n'est envoyé, conservé ni journalisé — et il n'y aurait pas grand-chose à journaliser : l'entrée est un nombre compris entre 0 et 255.