Signification de $? (point d'interrogation dollar) dans les scripts shell

178

Que fait

echo $?

signifie en programmation shell?

Harshay Buradkar
la source
état de sortie de la dernière commande
Shiwangini le

Réponses:

212

Il s'agit de l'état de sortie de la dernière commande exécutée.

Par exemple, la commande truerenvoie toujours un état de 0et falserenvoie toujours un état de 1:

true
echo $? # echoes 0
false
echo $? # echoes 1

Depuis le manuel: (accessible en appelant man bashvotre shell)

$?       S'étend au statut de sortie du pipeline de premier plan le plus récemment exécuté.

Par convention, un statut de sortie 0signifie succès et un statut de retour différent de zéro signifie échec. En savoir plus sur les statuts de sortie sur wikipedia .

Il existe d'autres variables spéciales comme celle-ci, comme vous pouvez le voir dans ce manuel en ligne: https://www.gnu.org/s/bash/manual/bash.html#Special-Parameters

Arnaud Le Blanc
la source
Notez $et ?sont deux paramètres distincts et $?n'apparaissent pas dans la page de manuel bash (1).
Josh Habdas
19

$?renvoie la valeur de sortie de la dernière commande exécutée. echo $?imprime cette valeur sur la console. zéro implique une exécution réussie tandis que les valeurs non nulles sont mappées à diverses raisons d'échec.

Par conséquent, lors de la création de scripts; J'ai tendance à utiliser la syntaxe suivante

if [ $? -eq 0 ]; then
 # do something
else
 # do something else
fi

La comparaison doit être faite sur un pied d'égalité 0ou non 0.

** Mise à jour Basé sur le commentaire: Idéalement, vous ne devriez pas utiliser le bloc de code ci-dessus pour la comparaison, reportez-vous aux commentaires et explications @tripleee.

Saurabh Ariyan
la source
15
Non, c'est un anti-modèle. Tout ce qui ressemble à cmd; if [ $? -eq 0 ]; thendevrait être refactorisé if cmd; then. Le but même de if(et des autres instructions de contrôle de flux dans le shell) est d'exécuter une commande et d'examiner son état de sortie.
tripleee
if cmd;certaines conditions peuvent ne pas être très lisibles, en particulier lorsque cmd fait référence à un autre script.
Saurabh Ariyan
1
C'est encore plus faux maintenant. [ 1 ]et [ 0 ]sont tous les deux vrais; [sans opérateur vérifie si l'argument est une chaîne non vide.
tripleee
2
Je suis sur le point de le faire vendor/bin/drush status bootstrap | grep -q $(vendor/bin/drush php-eval 'if (function_exists("t")) echo t("Successful");') &> /dev/null;. Si je devais mettre cela sur une seule ligne, if [ ... ]ce serait terriblement illisible. Je prévois de stocker la sortie de cette ligne dans une variable afin que je puisse le dire if [ $drupal_installed -eq 0 ]plus tard.
troisième porteur
1
@thirdender La solution appropriée à cela est d'encapsuler le test complexe dans une fonction shell.
tripleee
12

echo $? - Donne le STATUT DE SORTIE de la dernière commande exécutée . Ce STATUT DE SORTIE serait très probablement un nombre avec ZERO indiquant le succès et toute valeur NON-ZERO indiquant l' échec

? - Ceci est un paramètre / variable spécial dans bash.

$? - Il donne la valeur stockée dans la variable "?".

Certains paramètres spéciaux similaires dans BASH sont 1,2, *, # (normalement vu dans la commande echo comme $ 1, $ 2, $ *, $ #, etc.,).

Arun Karthik
la source
8

Il a le dernier code d'état (valeur de sortie) d'une commande.

Ned Batchelder
la source
5

Exemple d'état de sortie POSIX C minimal

Pour comprendre $?, vous devez d'abord comprendre le concept de statut de sortie de processus qui est défini par POSIX . Sous Linux:

  • lorsqu'un processus appelle l' exitappel système, le noyau stocke la valeur passée à l'appel système (unint ) même après la mort du processus.

    L'appel système de sortie est appelé par la exit()fonction ANSI C et indirectement lorsque vous le faites à returnpartir de main.

  • le processus qui a appelé le processus enfant sortant (Bash), souvent avec fork+ exec, peut récupérer le statut de sortie de l'enfant avec l' waitappel système

Considérez le code Bash:

$ false
$ echo $?
1

L '«équivalent» C est:

faux.c

#include <stdlib.h> /* exit */

int main(void) {
    exit(1);
}

bash.c

#include <unistd.h> /* execl */
#include <stdlib.h> /* fork */
#include <sys/wait.h> /* wait, WEXITSTATUS */
#include <stdio.h> /* printf */

int main(void) {
    if (fork() == 0) {
        /* Call false. */
        execl("./false", "./false", (char *)NULL);
    }
    int status;
    /* Wait for a child to finish. */
    wait(&status);
    /* Status encodes multiple fields,
     * we need WEXITSTATUS to get the exit status:
     * http://stackoverflow.com/questions/3659616/returning-exit-code-from-child
     **/
    printf("$? = %d\n", WEXITSTATUS(status));
}

Compilez et exécutez:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o bash bash.c
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o false false.c
./bash

Production:

$? = 1

Dans Bash, lorsque vous appuyez sur Entrée, un fork + exec + wait se produit comme ci-dessus, et bash définit ensuite $? l'état de sortie du processus forké.

Remarque: pour les commandes intégrées comme echo, un processus n'a pas besoin d'être généré, et Bash se règle simplement $?sur 0 pour simuler un processus externe.

Normes et documentation

POSIX 7 2.5.2 "Paramètres spéciaux" http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02 :

? S'étend à l'état de sortie décimal du pipeline le plus récent (voir Pipelines).

man bash "Paramètres spéciaux":

Le shell traite plusieurs paramètres spécialement. Ces paramètres ne peuvent être référencés que; leur attribution n'est pas autorisée. [...]

? S'étend au statut de sortie du pipeline de premier plan le plus récemment exécuté.

ANSI C et POSIX recommandent alors que:

  • 0 signifie que le programme a réussi

  • autres valeurs: le programme a échoué d'une manière ou d'une autre.

    La valeur exacte peut indiquer le type de panne.

    ANSI C ne définit pas la signification des vaues, et POSIX spécifie des valeurs supérieures à 125: Quelle est la signification de "POSIX"?

Bash utilise l'état de sortie pour if

Dans Bash, nous utilisons souvent le statut de sortie $?implicitement pour contrôler les ifinstructions comme dans:

if true; then
  :
fi

trueest un programme qui renvoie simplement 0.

Ce qui précède est équivalent à:

true
result=$?
if [ $result = 0 ]; then
  :
fi

Et en:

if [ 1 = 1 ]; then
  :
fi

[est juste un programme avec un nom étrange (et intégré à Bash qui se comporte comme lui), et 1 = 1 ]ses arguments, voir aussi: Différence entre les crochets simples et doubles dans Bash

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
3

Voir le manuel Bash sous 3.4.2 Paramètres spéciaux :

? - S'étend à l'état de sortie du pipeline de premier plan le plus récemment exécuté.

C'est un peu difficile à trouver car il n'est pas répertorié comme $?(le nom de la variable est "juste" ?). Voir aussi la section sur l' état de sortie , bien sûr ;-)

Bon codage.

Shubham
la source
2

Affiche le résultat de la dernière commande unix exécutée

0 implies true
1 implies false
Sojourner
la source