web-dev-qa-db-fra.com

Pourquoi est vrai mais faux est 1 dans la coquille?

false; echo $?

Ce qui précède générera 1, ce qui est contradictoire avec tous les autres langages de programmation que je connais.

Une raison à cela?

93
httpinterpret

C'est une convention, mais particulièrement utile quand on y pense. En général, si un programme réussit, c'est tout ce que vous devez savoir. Si cela échoue, cependant, vous aurez peut-être besoin de connaître toutes sortes d'informations sur cet échec: pourquoi, pourquoi-y-at-il eu lieu, comment le réparer, etc. , et recherchez l’erreur particulière pour plus de détails si vous le souhaitez. De nombreuses API et infrastructures ont une convention similaire: les fonctions qui aboutissent renvoient 0 et celles qui échouent, renvoient un code d'erreur décrivant le cas d'échec particulier.

75
Carl Norum

Bash est un langage de programmation (script), mais c'est aussi un shell et une interface utilisateur. Si 0 était une erreur, le programme ne pouvait présenter qu'un seul type d'erreur.

Cependant, dans Bash, toute valeur non nulle est une erreur et nous pouvons utiliser un nombre compris entre 1 et 255 pour représenter une erreur. Cela signifie que nous pouvons avoir de nombreux types d’erreurs. 1 est une erreur générale, 126 signifie qu'un fichier ne peut pas être exécuté, 127 signifie «commande introuvable», etc. Voici une liste des codes de sortie Bash avec des significations spéciales indiquant certains des codes de sortie les plus courants.

Il existe également de nombreux types de réussite (le statut de sortie est 0). Cependant, un succès vous permettra de passer à l'étape suivante - vous pouvez aimer imprimer les résultats sur un écran, exécuter une commande, etc. 

56
Stefan Lasiewski

Il y a deux problèmes liés ici.

Premièrement, la question de l'OP, Pourquoi 0 est vrai mais faux est 1 dans la coquille? et le second, pourquoi les applications renvoient 0 en cas de succès et non nul en cas d'échec? 

Pour répondre à la question du PO, nous devons comprendre la deuxième question. Les nombreuses réponses à ce message ont indiqué qu'il s'agissait d'une convention et ont énuméré certaines des subtilités offertes par cette convention. Certaines de ces subtilités sont résumées ci-dessous.

Pourquoi les applications renvoient-elles 0 en cas de succès et non nul en cas d'échec?

Le code qui appelle une opération doit connaître deux choses sur l'état de sortie de l'opération. L'opération s'est-elle terminée avec succès? [* 1] Et si l'opération ne se ferme pas correctement pourquoi l'opération s'est-elle terminée sans succès? Toute valeur peut être utilisée pour indiquer le succès. Mais 0 est plus pratique que n’importe quel autre numéro car il est portable entre les plates-formes. Résumant la réponse de xibo à cette question question du 16 août 2011:

Zéro est indépendant du codage. 

Si nous voulions en stocker un (1) dans un mot entier de 32 bits, la première question serait «mot big-endian ou mot petit-endien?», Suivi de «combien de temps les octets composant un mot petit-endien? ", alors que zéro sera toujours le même.

En outre, il faut s’attendre à ce que certaines personnes jettent errno dans charo ou short à un moment donné, ou même qu’elles flottent. (int) ((char) ENOLCK) n'est pas ENOLCK lorsque la longueur du caractère n'est pas d'au moins 8 bits (les machines à caractères de 7 bits ASCII sont prises en charge par UNIX), tandis que (int) ((char) 0) est pris en charge. 0 indépendant des détails architecturaux de char.

Une fois qu'il est déterminé que 0 sera la valeur de retour de succès, il est alors logique d'utiliser toute valeur non nulle en cas d'échec. Cela permet à plusieurs codes de sortie de répondre à la question pourquoi l’opération a échoué.

Pourquoi 0 est vrai mais faux est 1 dans la coquille?

L'un des usages fondamentaux des shells est d'automatiser les processus en les scriptant. Habituellement, cela signifie qu’il faut invoquer une opération puis faire autre chose de manière conditionnelle en fonction du statut de sortie de l’opération. Philippe A. a bien expliqué dans sa réponse à ce message que 

Dans les shell bash et unix en général, les valeurs de retour ne sont pas des valeurs booléennes . Ce sont des codes de sortie entiers.

Il faut ensuite interpréter le statut de sortie de ces opérations comme une valeur booléenne. Il est logique de mapper un statut de sortie réussi (0) sur true et tout statut de sortie autre que zéro/échec sur false. Cela permet l'exécution conditionnelle des commandes Shell chaînées.

Voici un exemple mkdir deleteme && cd $_ && pwd. Comme le shell interprète 0 comme vrai, cette commande fonctionne normalement comme prévu. Si le shell interprète 0 comme faux, vous devez inverser le statut de sortie interprété pour chaque opération.

En bref, il serait absurde que Shell interpréte 0 comme faux, étant donné la convention selon laquelle les applications renvoient 0 si l'état de sortie est correct.


[* 1]: Oui, bien souvent, les opérations doivent renvoyer plus qu'un simple message de réussite, mais cela dépasse la portée de ce fil.

Voir aussi Annexe E dans le Guide avancé de script Bash

24
axiopisty

Le point fondamental que je trouve important à comprendre est le suivant. Dans les shell bash et unix en général, les valeurs de retour ne sont pas booléennes. Ce sont des codes de sortie entiers. En tant que tel, vous devez les évaluer selon la convention en disant que 0 signifie le succès, et les autres valeurs signifient une erreur.

Avec les opérateurs test, [ ] ou [[ ]], les conditions bash sont considérées comme vraies si le code de sortie est 0 (résultat de/bin/true). Sinon, ils sont évalués comme faux.

Les chaînes sont évaluées différemment des codes de sortie:

if [ 0 ] ; then echo not null ; fi
if [ $(echo 0) ] ; then echo not null ; fi

if [ -z "" ] ; then echo null ; fi

L'opérateur arithmétique (( )) interprète les valeurs 1 et 0 comme vraies et fausses. Mais cet opérateur ne peut pas être utilisé en remplacement complet de test, [ ] ou [[ ]]. Voici un exemple montrant quand l'opérateur arithmétique est utile:

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
  if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done
15
Philippe A.

C'est juste une convention qu'un code de sortie 0 signifie le succès. EXIT_SUCCESS sera 0 sur presque tous les systèmes modernes.

MODIFIER:

"pourquoi les tests 0 et 1 renvoient-ils 0(success)?"

C'est une question complètement différente. La réponse est que le fait de passer un seul argument à tester entraîne toujours le succès, à moins que cet argument ne soit la chaîne nulle (""). Voir la documentation du groupe Open Group .

14
Matthew Flaschen

Généralement, les programmes renvoient zéro en cas de succès, non nul en cas d'échec; false renvoie 1 car il s'agit d'une valeur pratique non nulle, mais toute valeur autre que zéro est généralement synonyme d'échec, et de nombreux programmes renvoient différentes valeurs non nulles pour indiquer différents modes d'échec

11
Michael Mrozek

Autant que je sache, cela provient de la convention C selon laquelle vous devez renvoyer 0 en cas de succès ... Voir.

man close

La plupart de l’API C (POSIX) est construite de cette façon http://en.wikipedia.org/wiki/C_POSIX_library

4
mathk

c'est une convention qui remonte aux débuts d'Unix.

Par convention, tous les appels système renvoient 0 si ils réussissent, non nuls sinon, car des nombres différents peuvent être utilisés pour indiquer une raison d'échec différente.

Les shells suivent cette convention, 0 signifie que la dernière commande a réussi, sinon zéro. De même, la valeur de retour non nulle est pratique pour les messages d'erreur en sortie: par ex. 1: "mort cérébrale", 2: "sans coeur", et ainsi de suite.

3
user1252446

Vous essayez d’assimiler vrai/faux à succès/échec. 

Ce sont deux dichotomies complètement différentes, bien que subtiles au début!

Dans les scripts Shell, il n'y a pas de vrai/faux. Les expressions du shell ne sont pas interprétées comme vraies/fausses. Les expressions de Shell sont des processus qui réussissent ou échouent.

De toute évidence, un processus peut échouer pour plusieurs raisons. Nous avons donc besoin d’un ensemble de codes plus large pour identifier les défaillances possibles. Les entiers positifs font l'affaire. D'autre part, si le processus aboutit, cela signifie qu'il a fait exactement ce qu'il était censé faire. Comme il n’ya qu’une façon de faire cela, nous n’avons besoin que d’un code. 0 fait le tour.

En C, nous créons un programme. Dans un script Shell, nous exécutons de nombreux programmes pour accomplir quelque chose.

Différence!

3
captaincurrie

Peut-être un bon moyen de s'en souvenir est:

  • Les codes de retour répondent "quelle est la réponse?" vrai (ou autre résultat) ou faux
  • Les codes de sortie répondent "quel est le problème?" code de sortie ou pas de problème (0)
0
jjisnow