Quelle est la meilleure pratique pour représenter une valeur booléenne dans un script shell?

15

Je sais qu'il y a des valeurs booléennes dans bash, mais je ne les vois jamais utilisées nulle part.

Je veux écrire un wrapper pour certaines informations souvent recherchées sur ma machine, par exemple, ce lecteur USB particulier est-il inséré / monté.

Quelle serait la meilleure pratique pour y parvenir?

  • Un string?

    drive_xyz_available=true
  • Un nombre (0 pour vrai, ≠ 0 pour faux)?

    drive_xyz_available=0    # evaluates to true
  • Une fonction?

    drive_xyz_available() { 
        if available_magic; then 
                return 0 
        else 
                return 1 
        fi
    }

Je me demande surtout ce à quoi s'attendraient d'autres personnes qui voudraient utiliser le wrapper. S'attendraient-ils à une valeur booléenne, une commande comme une variable ou une fonction à appeler?

Du point de vue de la sécurité, je pense que la deuxième option est la plus sûre, mais j'aimerais entendre vos expériences.

Minix
la source
3
help true ; help false ; help exit
Costas
3
@Costas Pourriez-vous élaborer?
Minix

Réponses:

2
bool(){ return "$((!${#1}))"; }

if bool "$var"
then : do true
else : do false

Définissez simplement une variable sur n'importe quoi, mais pas sur null pour que ce qui précède fonctionne, mais [ -n "$var" ]serait plus court, sinon aussi évident.

En général, lorsqu'un script interprète une variable d'environnement comme vraie ou fausse, il interprète n'importe quelle valeur comme vraie (et utilise parfois cette valeur pour configurer une option) ou bien une valeur nulle comme fausse.

Ce qui précède renvoie la !notvaleur booléenne du len de son premier argument - si l'argument contient un nombre de caractères différent de 0, il renvoie 0, sinon, s'il n'y a pas de caractères du tout, il renvoie 1. C'est le même test que vous pouvez effectuer avec [ -n "$var" ], en gros , mais il l'enveloppe simplement dans une petite fonction nommée bool().

C'est généralement ainsi que fonctionne une variable indicateur . Par exemple:

[ -d "$dir" ] || dir=

Là où d'autres parties d'un script n'ont besoin que de rechercher une valeur $dirpour évaluer son utilité. Cela est également utile en ce qui concerne la substitution de paramètres - car les paramètres peuvent être étendus aux valeurs par défaut pour être remplacés par des paramètres vides ou non définis, mais se développeront autrement à une valeur prédéfinie comme ...

for set in yes ''
do echo "${set:-unset or null}"
done

... qui imprimerait ...

yes
unset or null

Bien sûr, il est également possible de faire le contraire avec :+mais cela ne peut que vous donner un défaut prédéfini ou rien du tout, tandis que le formulaire ci-dessus peut vous donner une valeur ou une valeur par défaut.

Et donc en ce qui concerne les trois choix - chacun pourrait fonctionner selon la façon dont vous choisissez de le mettre en œuvre. Le retour de la fonction est auto-test, mais, si ce retour doit être sauvegardé pour une raison quelconque, il devra être mis dans une variable. Cela dépend du cas d'utilisation - la valeur booléenne que vous souhaitez évaluer un test une fois et est-elle de type? Si c'est le cas, faites la fonction, sinon l'un des deux autres est probablement nécessaire.

mikeserv
la source
1
Je ne pense pas que vous répondiez à ma question. Je ne demande pas comment les booléens pourraient être utilisés dans un script shell, mais quelle est la manière la plus courante et attendue par un autre utilisateur. Si ma question n'est pas claire, je serais heureuse de la modifier. Une brève explication de ce que fait votre réponse serait également intéressante. Je vous remercie.
Minix
@Minix Quoi de mieux?
mikeserv
truefalseif $variable; then ...
J'attribue
@wurtel - qui repose sur la valeur par défaut $IFS- et si la valeur de la var peut contenir des entrées utilisateur de toute nature, alors aussi bonne chance. Si la valeur n'est pas inconnue au départ, il n'est pas nécessaire de la tester. Vous pouvez le faire en toute sécurité if ${var:+":"} false; thenlorsque vous travaillez avec des valeurs booléennes null / not null. Mais c'est rarement plus utile que[ -n "$var" ] &&
mikeserv
Si je démarre mon script avec variable=falsepuis le définit sur true en fonction de la condition (comme je le ferais lors de l'utilisation d'une variable en C), il n'y a aucun problème, quelle est votre obsession de faire varier les valeurs IFS et les valeurs de variables aléatoires, etc. de toute façon .. .
Wurtel
4

Dans bashchaque variable se trouve essentiellement une chaîne (ou un tableau ou une fonction, mais parlons ici des variables régulières).

Les conditions sont analysées en fonction des valeurs de retour des commandes de test - la valeur de retour n'est pas une variable, c'est un état de sortie. Lorsque vous évaluez if [ ... ]ou if [[ ]]ou if grep somethingou quelque chose comme ça, la valeur de retour 0 (pas la chaîne 0, mais l'état de sortie 0 = succès) signifie vrai et le reste signifie faux (donc, exactement le contraire de ce à quoi vous êtes habitué dans les langages de programmation compilés, mais comme il existe un moyen de réussir et de nombreuses façons d'échouer, et que le résultat attendu de l'exécution est généralement un succès, 0 est utilisé comme résultat par défaut le plus courant si rien ne va mal). C'est très utile car tout binaire peut être utilisé comme test - s'il échoue, c'est faux, sinon c'est vrai.

trueet les falseprogrammes (généralement remplacés par les prédéfinis) ne sont que de petits programmes utiles qui ne font rien - trueréussissent à ne rien faire et se terminent par 0, tandis qu'ils falseessaient de ne rien faire et "échouent", se terminant par 1. Cela semble inutile mais c'est très pratique pour l'écriture de scripts.

Quant à savoir comment transmettre la vérité, c'est à vous de décider. Il est assez courant d'utiliser simplement "y" ou "oui" pour la vérité et l'utilisation if [ x"$variable" = x"yes" ](en ajoutant la chaîne factice xparce que s'il $variablese trouve être de longueur nulle, cela protège de la création d'une fausse commande if [ = "yes" ]qui n'analyse pas). Il peut également être utile d'utiliser simplement une chaîne vide pour false et [ -z "$variable ]de tester si sa longueur est nulle (ou -npour qu'elle soit différente de zéro).

Quoi qu'il en soit, il est assez rare de devoir passer des valeurs booléennes dans bash- il est beaucoup plus courant de simplement exiten cas d'échec, ou de retourner un résultat utile (ou zéro en cas de problème et de tester une chaîne vide), et la plupart des cas peuvent tester l'échec directement à partir du statut de sortie.


Dans votre cas, vous voulez une fonction qui agira comme n'importe quelle autre commande (par conséquent, retourne 0 en cas de succès), donc votre dernière option semble le bon choix.

De plus, vous n'aurez peut-être même pas besoin de returndéclaration. Si la fonction est assez simple, vous pouvez utiliser le fait qu'elle renvoie simplement l'état de la dernière commande exécutée dans la fonction. Ainsi, votre fonction peut simplement être

drive_xyz_available() {
   [ -e /dev/disk/by-uuid/whatever ]
}

si vous testez l'existence d'un nœud de périphérique (ou grep /proc/mountspour vérifier s'il est monté?).

orion
la source
C'est un très joli résumé, merci d'avoir pris le temps de le rédiger. Puis-je déduire de votre dernier paragraphe que vous considérez que l'option drive_xyz_available()est la plus courante?
Minix
Pouvez-vous fournir des exemples pour le y = truecas commun ? D'après mon expérience, la plupart des scripts wrapper testent toute valeur non nulle pour la considérer comme vraie - du moins en ce qui concerne les variables d'environnement interprétées. Sinon, ils ignorent complètement les voitures obus.
mikeserv
3
La chaîne fictive pour le iftest n'est pas nécessaire si la variable est citée; if [ "$variable" = "yes" ]fonctionne bien même si $ variable n'est pas défini.
daniel kullmann
-2

Fondamentalement, tout nombre différent de 0 est vrai et 0 est faux. Raison du retour des valeurs à 0 pour une fin réussie d'un script ou de tout autre nombre afin d'identifier différents types d'erreurs.

$? renverra le code de sortie de la commande / exécutable précédente, soit 0 succès et tout autre numéro l'erreur qui a été renvoyée.

J'utiliserais donc cette méthode pour vrai / faux. if (( ! $? ));then OK;else NOOK;fi

YoMismo
la source
Je vais en écrire un pour la dernière option, alors. Je vous remercie.
Minix
5
Un nombre différent de zéro est faux et zéro est vrai. Regardez simplement la sortie de true; echo $?et false; echo $?.
Ruslan
@Ruslan. Avez-vous vérifié la sortie de ma commande? Je suppose que vous ne l'avez pas fait, sinon vous n'auriez pas dit ce que vous avez fait. 0 est faux, tout autre nombre est vrai, raison d'annuler !le résultat pour qu'il soit VRAI. Le résultat d'une commande est 0 lorsqu'elle s'est terminée correctement, ce qui ne signifie pas que 0 est vrai. Le mot truepeut être 0, mais 0 n'est jamais vrai comme le ifmontre la condition.
YoMismo
Cela 0revient à dire qu'en C / C ++, c'est trueparce que if(!x){True();}else{False();}va appeler True()quand x==0. Mais la vérification correcte ne serait pas !x, mais plutôt !!x.
Ruslan
Vous vous trompez waaaaaaay. Je ne parle pas de quoi et de quel ordre a tout ce que vous écrivez après le ifje déclare simplement le fait qu'ici (en bash, ou ksh, ou tsh, ou ....) comme en C / C ++ un 0 est FAUX, tout un autre nombre est VRAI, comme vous pouvez le lire dans le lien qui suit, les implémentations initiales de C n'ont fourni aucun type booléen, étant définies comme des entiers où 0 était FAUX et 1 VRAI en.wikipedia.org/wiki/Boolean_data_type .
YoMismo