Come uscire da uno script in un'istruzione condizionale?


50

Sto scrivendo uno script bash in cui voglio uscire se l'utente non è root. Il condizionale funziona bene, ma lo script non esce.

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

Ho provato a utilizzare &&invece di ;ma nessuno dei due ha funzionato.

Risposte:


50

Puoi farlo in questo modo:

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

(espressione condizionale "ordinaria" con un operatore binario aritmetico nella prima istruzione), oppure:

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

(valutazione aritmetica per il primo test).

Notare la modifica ()-> {}- le parentesi graffe non generano una subshell. (Cerca man bash"subshell".)


1
Si prega di uscire con un codice diverso da zero, esempio: exit 1per comprendere il processo padre che si è verificato un problema.
SamK,

1
Non dovresti usare [[per il confronto numerico, usa ((.
Chris Down,

1
@ChrisDown [[va bene, purché usi -eqinvece di ==.
Let_Me_Be

Risolto il problema condizionale, aggiunta la versione aritmetica, @ChrisDown.
Mat

2
@Mat A proposito, puoi accorciarlo a(( EUID )) && ...
Chris Down,

21

Le parentesi attorno a questi comandi creano una subshell . La tua subshell echos "Deve essere root per eseguire lo script" e poi dici alla subshell di uscire (anche se lo avrebbe già fatto, dato che non c'erano più comandi). Il modo più semplice per risolverlo è probabilmente usare solo un if:

if [[ `id -u` != 0 ]]; then
    echo "Must be root to run script"
    exit
fi

Quindi non c'è modo di farlo con un one-liner?
Garrett Hall,

1
la tua logica è al contrario. nel tuo esempio, se id -u == 0, il che significa che si è root. Tu vuoi [[ $(id -u) != 0 ]]; then.
Tim Kennedy,

4
Se devi / devi avere un solo strato, prova questo per dimensioni: [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1;nota anche il $UID, che salva la generazione di un processo. Penso che potresti persino preferire $EUID.
Janmoesen,

1
@janmoesen, buon punto. E mentre wee avere una variabile con un valore numerico: ((UID)) && echo 'You have to be root.' && exit 1.
arte

3
@janmoesen: notare che l'uso di tale logica inversa causerà uno script che si set -einterromperà. Una soluzione a questo problema è [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1 || true.
sam hocevar,

2

Con bash :

[ $UID -ne 0 ] && echo "Must be root to run script" && exit 1

Ciò non riuscirebbe ad uscire se echofallisce (ad esempio perché stdout non è scrivibile).
Stéphane Chazelas,

1

Le parentesi intorno ||e &&non sono necessarie in quanto associative. Le seguenti due espressioni sono equivalenti:

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

Quindi &&invece di ;funzionerebbe bene, poiché echotornerà vero.

[[ $(id -u) == 0 ]] || echo "Must be root to run script" && exit 1

1
Mentre tutto ciò che hai detto è corretto, questo è un modello errato da imparare, perché stai facendo affidamento sul valore di ritorno di expr2. Sei sicuro che l'eco restituirà sempre uno stato di uscita 0? È molto meglio raggruppare le dichiarazioni con parentesi graffe e punti e virgola. Si tratta di una trappola così comune che ha una propria voce in BashPitfalls: mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3
Flimm

1
@Flimm: non sono d'accordo che sia un cattivo modello. Evidentemente, dipende dal caso e dipende anche dalla tua conoscenza dei valori di ritorno che otterrai. In questo caso sono sicuro che l'eco restituirà 0 il 99,999% delle volte e se si verifica un errore di scrittura (l'unico caso in cui non restituirà 0) c'è un problema più grande di questo expr. C'è anche il caso in cui TU stai generando i valori di ritorno, quindi no, non è un "cattivo modello" di per sé per me.
ata

Aggiungerò anche, come si dice nel wiki, che dovresti usarlo se sei sicuro di capire la valutazione C. Ad ogni modo, un piccolo test dovrebbe chiarire eventuali ambiguità.
ata

0

questo potrebbe aiutarti, in 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

3
Questo ha già ricevuto risposta e accettato. Inoltre, la tua risposta è quasi identica a ciò che è già stato pubblicato.
Maulinglawns

@maulinglawns, quella risposta, contrariamente alle altre ha il merito di essere portabile su tutte le shell tipo Bourne (sarebbe meglio se l'errore fosse emesso su stderr, lo stato di uscita fosse diverso da zero e la sostituzione del comando sarebbe stata citata comunque )
Stéphane Chazelas il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.