Wie verlasse ich ein Skript in einer bedingten Anweisung?

50

Ich schreibe ein Bash-Skript, in dem ich beenden möchte, wenn der Benutzer nicht root ist. Die Bedingung funktioniert einwandfrei, aber das Skript wird nicht beendet.

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

Ich habe versucht, &&anstatt ;aber keine Arbeit zu verwenden.

Garrett Hall
quelle

Antworten:

50

Das könnten Sie so machen:

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

("gewöhnlicher" Bedingungsausdruck mit einem arithmetischen Binäroperator in der ersten Anweisung) oder:

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

(arithmetische Auswertung für den ersten Test).

Beachten Sie die Änderung ()-> {}- die geschweiften Klammern erzeugen keine Unterschale. (Suche man bashnach "Subshell".)

Matte
quelle
1
Beenden Sie exit 1den Vorgang mit einem anderen Code als Null. Beispiel: Damit Sie den übergeordneten Prozess verstehen, bei dem ein Problem aufgetreten ist.
SamK
1
Sie sollten nicht [[für den numerischen Vergleich verwenden, verwenden ((.
Chris Down
1
@ChrisDown [[ist in Ordnung, solange Sie -eqstatt verwenden ==.
Let_Me_Be
Korrigierte die Bedingung und fügte die arithmetische Version @ChrisDown hinzu.
Mat
2
@ Mat Übrigens können Sie es auf(( EUID )) && ...
Chris Down
21

Die Klammern um diese Befehle erstellen eine Unterschale . In Ihrer Subshell wird das Echo "Muss root sein, um das Skript auszuführen" angezeigt , und Sie weisen die Subshell an , das Skript zu beenden (obwohl dies bereits geschehen wäre, da keine weiteren Befehle vorhanden waren). Der einfachste Weg, dies zu beheben, besteht wahrscheinlich darin, einfach Folgendes zu verwenden if:

if [[ `id -u` != 0 ]]; then
    echo "Must be root to run script"
    exit
fi
Michael Mrozek
quelle
Also gibt es keine Möglichkeit, dies mit einem Einzeiler zu tun?
Garrett Hall,
1
Ihre Logik ist rückwärts. wenn in Ihrem Beispiel id -u == 0, das würde bedeuten , dass Sie sind root. Sie möchten [[ $(id -u) != 0 ]]; then.
Tim Kennedy
4
Wenn Sie einen Einzeiler haben / müssen / müssen, probieren Sie dies für die Größe an: [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1;Beachten Sie auch das $UID, was das Laichen eines Prozesses erspart. Ich denke, Sie könnten es sogar vorziehen $EUID.
Januar
1
@janmoesen, guter Punkt. Und während die Kleinsten haben eine Variable mit einem numerischen Wert: ((UID)) && echo 'You have to be root.' && exit 1.
Manatwork
3
@janmoesen: Beachten Sie, dass bei Verwendung einer solchen inversen Logik ein Skript abgebrochen wird set -e. Eine Lösung für dieses Problem ist [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1 || true.
Sam Hocevar
2

Mit Bash :

[ $UID -ne 0 ] && echo "Must be root to run script" && exit 1
Cyrus
quelle
Das kann nicht beendet werden, wenn dies echofehlschlägt (z. B. weil stdout nicht beschreibbar ist).
Stéphane Chazelas
1

Klammern um ||und &&sind nicht erforderlich, da diese rechtsassoziativ sind. Die folgenden zwei Ausdrücke sind äquivalent:

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

Also &&anstatt ;würde es gut funktionieren, da echowird es wieder wahr.

[[ $(id -u) == 0 ]] || echo "Must be root to run script" && exit 1
an einer
quelle
1
Obwohl alles, was Sie gesagt haben, korrekt ist, ist dies ein schlechtes Lernmuster, da Sie sich auf den Rückgabewert von expr2 verlassen. Sind Sie sicher, dass das Echo immer den Beendigungsstatus 0 zurückgibt? Es ist viel besser, die Anweisungen mit geschweiften Klammern und Semikolons zu gruppieren. Dies ist eine so häufige Gefahr, dass es einen eigenen Eintrag in BashPitfalls gibt: mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3
Flimm
1
@Flimm: Ich stimme nicht zu, dass es ein schlechtes Muster ist. Offensichtlich ist die Verwendung von Groß- und Kleinschreibung abhängig und hängt auch von Ihrer Kenntnis der Rückgabewerte ab, die Sie erhalten. In diesem Fall wird das Echo in 99,999% der Fälle 0 zurückgeben, und wenn es bei einem Schreibfehler auftritt (der einzige Fall, dass es nicht 0 zurückgibt), liegt ein größeres Problem vor als dieser Ausdruck. Es gibt auch den Fall, dass SIE die Rückgabewerte generieren, also nein, es ist kein "schlechtes Muster" an sich für mich.
ata
Ich werde auch hinzufügen, wie es im Wiki steht, dass du es verwenden solltest, wenn du sicher bist, dass du die C-Bewertung verstehst. Auf jeden Fall sollten ein paar Tests Unklarheiten beseitigen.
ata
0

das könnte dir helfen, 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
sandeep kazipeta
quelle
3
Dies wurde bereits beantwortet und akzeptiert. Außerdem ist Ihre Antwort nahezu identisch mit der bereits veröffentlichten.
Maultinglawns
@maulinglawns, diese Antwort hat im Gegensatz zu den anderen den Vorzug, auf alle Bourne-ähnlichen Shells portierbar zu sein (es wäre besser, wenn der Fehler auf stderr ausgegeben würde, der Exit-Status ungleich Null wäre und die Befehlsersetzung jedoch in Anführungszeichen gesetzt würde )
Stéphane Chazelas