Comment puis-je quitter un script dans une instruction conditionnelle?

50

J'écris un script bash où je veux sortir si l'utilisateur n'est pas root. Le conditionnel fonctionne bien, mais le script ne se ferme pas.

[[ `id -u` == 0 ]] || (echo "Must be root to run script"; exit)

J'ai essayé d'utiliser &&au lieu de, ;mais ni travail.

Garrett Hall
la source

Réponses:

50

Vous pouvez le faire de cette façon:

[[ $(id -u) -eq 0 ]] || { echo >&2 "Must be root to run script"; exit 1; }

(expression conditionnelle "ordinaire" avec un opérateur binaire arithmétique dans la première instruction), ou:

(( $(id -u) == 0 )) || { echo >&2 "Must be root to run script"; exit 1; }

(évaluation arithmétique pour le premier test).

Notez le changement ()-> {}- les accolades ne génèrent pas de sous-shell. (Recherchez man bash"subshell".)

Tapis
la source
1
Veuillez quitter avec un code autre que zéro, exemple: exit 1afin de faire comprendre au processus parent qu'un problème est survenu.
SamK
1
Vous ne devriez pas utiliser [[pour la comparaison numérique, utilisez ((.
Chris Down
1
@ChrisDown [[est bien, tant que vous utilisez -eqau lieu de ==.
Let_Me_Be
Correction du conditionnel, ajout de la version arithmétique, @ChrisDown.
Mat
2
@Mat Par ailleurs, vous pouvez le raccourcir à(( EUID )) && ...
Chris Down
21

Les parenthèses autour de ces commandes créent un sous - shell . Votre sous-shell renvoie "Doit être la racine pour exécuter le script", puis vous indiquez au sous - shell de quitter (bien qu'il l'aurait déjà fait puisqu'il n'y avait plus de commandes). Le moyen le plus simple de résoudre ce problème consiste probablement à utiliser simplement if:

if [[ `id -u` != 0 ]]; then
    echo "Must be root to run script"
    exit
fi
Michael Mrozek
la source
Il n'y a donc aucun moyen de faire cela avec un one-liner?
Garrett Hall
1
votre logique est à l'envers. dans votre exemple, if id -u == 0, ce qui voudrait dire que vous êtes root. Vous voulez [[ $(id -u) != 0 ]]; then.
Tim Kennedy
4
Si vous / devez / avez un one-liner, essayez-le pour sa taille: [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1;Notez également le $UID, qui enregistre le processus de génération. Je pense que vous pourriez même préférer $EUID.
janmoesen
1
@janmoesen, bon point. Et tout petit une variable avec une valeur numérique: ((UID)) && echo 'You have to be root.' && exit 1.
Manatwork
3
@janmoesen: notez que l'utilisation d'une telle logique inverse entraînera l'abandon d'un script set -e. Une solution à ce problème est [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1 || true.
Sam Hocevar
2

Avec bash :

[ $UID -ne 0 ] && echo "Must be root to run script" && exit 1
Cyrus
la source
Cela échouerait si vous echoéchouiez (par exemple parce que stdout n'est pas accessible en écriture).
Stéphane Chazelas
1

Les crochets autour ||et &&ne sont pas nécessaires car ils sont associatifs à droite. Les deux expressions suivantes sont équivalentes:

expr1 || expr2 && expr3
expr1 || { expr2 && expr3 }

Donc, &&au lieu de ;fonctionnerait parfaitement, car echocela reviendra vrai.

[[ $(id -u) == 0 ]] || echo "Must be root to run script" && exit 1
à
la source
1
Bien que tout ce que vous avez dit soit correct, c'est un mauvais modèle à apprendre, car vous vous fiez à la valeur de retour de expr2. Etes-vous certain que l'écho retournera toujours un état de sortie 0? Il est bien préférable de regrouper les déclarations avec des accolades et des points-virgules. C'est un piège si courant qu'il a sa propre entrée dans BashPitfalls: mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3
Flimm
1
@ Flimm: Je ne suis pas d'accord, c'est un mauvais schéma. Évidemment, son utilisation dépend de la casse et de votre connaissance des valeurs de retour que vous obtiendrez. Dans ce cas, je suis sûr que echo renverra 99,999% des fois, et si il écrase une erreur d'écriture (le seul cas où il ne renverra pas 0), le problème est plus grave que celui-ci. Il y a aussi le cas où VOUS générez les valeurs de retour, donc non, ce n'est pas un "mauvais modèle" en tant que tel.
Ata
J'ajouterai aussi, comme il est dit dans le wiki, que vous devriez l'utiliser si vous êtes sûr de comprendre l'évaluation C. Quoi qu'il en soit, un peu de test devrait lever toutes les ambiguïtés.
Ata
0

cela pourrait vous aider, en bash

[oracle@rac1 ~]$ which bash
/bin/bash
[oracle@rac1 ~]$ cat test1.sh
if [ `id -u` != 0 ]
then
echo "Must be root to run the script
 "
exit
fi
Sandeep Kazipeta
la source
3
Cela a déjà été répondu et accepté. De plus, votre réponse est presque identique à ce qui a déjà été posté.
Maulinglawns
@maulinglawns, cette réponse, contrairement aux autres, a le mérite d'être portable pour tous les shells de type Bourne (il serait préférable que l'erreur soit sortie sur stderr, l'état de sortie était différent de zéro et la substitution de commande citée )
Stéphane Chazelas