Jak wyjść ze skryptu w instrukcji warunkowej?

50

Piszę skrypt bash, w którym chcę wyjść, jeśli użytkownik nie jest rootem. Warunkowe działa dobrze, ale skrypt nie kończy działania.

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

Próbowałem użyć &&zamiast, ;ale nie działa.

Garrett Hall
źródło

Odpowiedzi:

50

Możesz to zrobić w ten sposób:

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

(„zwykłe” wyrażenie warunkowe z arytmetycznym operatorem binarnym w pierwszej instrukcji) lub:

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

(ocena arytmetyczna dla pierwszego testu).

Zwróć uwagę na zmianę ()-> {}- nawiasy klamrowe nie odradzają podpowłoki. (Wyszukaj man bash„subshell”.)

Mata
źródło
1
Wyjdź z kodem innym niż zero, na przykład: exit 1aby zrozumieć proces nadrzędny, w którym wystąpił problem.
SamK,
1
Nie powinieneś używać [[do porównywania numerycznego, użyj ((.
Chris Down,
1
@ChrisDown [[jest w porządku, o ile używasz -eqzamiast ==.
Let_Me_Be
Naprawiono warunkowe, dodano wersję arytmetyczną @ChrisDown.
Mat
2
@Mata Przy okazji, możesz go skrócić do(( EUID )) && ...
Chris Down
21

Nawiasy wokół tych poleceń tworzą podpowłokę . Twoje echo podpowłoki „Musi być rootem, aby uruchomić skrypt”, a następnie każesz podpowłoce wyjść (chociaż już by to zrobił, ponieważ nie było więcej poleceń). Najłatwiejszym sposobem, aby to naprawić, jest prawdopodobnie użycie if:

if [[ `id -u` != 0 ]]; then
    echo "Must be root to run script"
    exit
fi
Michał Mrożek
źródło
Więc nie ma sposobu, aby to zrobić za pomocą jednego linera?
Garrett Hall,
1
twoja logika jest odwrócona. w przykładzie, jeśli id -u == 0, co oznaczałoby, że głównym. Chcesz [[ $(id -u) != 0 ]]; then.
Tim Kennedy,
4
Jeśli masz / musisz / masz jedną linijkę, wypróbuj to dla rozmiaru: [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1;Zwróć również uwagę na $UID, co oszczędza proces odradzania. Myślę, że może wolisz $EUID.
janmoesen
1
@janmoesen, dobry punkt. I choć wee mieć zmienną o wartości liczbowej: ((UID)) && echo 'You have to be root.' && exit 1.
manatwork
3
@janmoesen: zauważ, że użycie takiej odwrotnej logiki spowoduje, że skrypt przerwie działanie set -e. Jednym z rozwiązań tego problemu jest [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1 || true.
sam hocevar,
2

Z uderzeniem :

[ $UID -ne 0 ] && echo "Must be root to run script" && exit 1
Cyrus
źródło
To nie wyjdzie, jeśli się echonie powiedzie (na przykład, ponieważ standardowe wyjście nie jest zapisywalne).
Stéphane Chazelas,
1

Wsporniki wokół ||i &&nie są wymagane, ponieważ są odpowiednio skojarzone. Następujące dwa wyrażenia są równoważne:

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

Więc &&zamiast ;działałoby dobrze, jak echopowróci prawda.

[[ $(id -u) == 0 ]] || echo "Must be root to run script" && exit 1
ata
źródło
1
Chociaż wszystko, co powiedziałeś, jest poprawne, jest to zły wzorzec do nauczenia się, ponieważ polegasz na wartości zwracanej expr2. Czy jesteś pewien, że echo zawsze zwróci status wyjścia 0? O wiele lepszym pomysłem jest grupowanie instrukcji za pomocą nawiasów klamrowych i średników. Jest to tak częsta pułapka, że ​​ma swój własny wpis w BashPitfalls: mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3
Flimm 10.11.11
1
@Flimm: Nie zgadzam się, że to zły wzór. Oczywiście użycie jest zależne od wielkości liter, a także zależy od twojej wiedzy na temat zwracanych wartości. W tym przypadku jestem pewien, że echo zwróci 0 99,999% razy, a jeśli uderzy w błąd zapisu (jedyny przypadek nie zwróci 0), jest większy problem niż ten wyra. Jest też przypadek, w którym TY generujesz zwracane wartości, więc nie, to nie jest dla mnie „zły wzór”.
ata
Dodam też, jak mówi wiki, że powinieneś go użyć, jeśli na pewno rozumiesz ocenę C. W każdym razie trochę testów powinno usunąć wszelkie niejasności.
ata
0

to może ci pomóc w 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
źródło
3
To zostało już odebrane i zaakceptowane. Twoja odpowiedź jest prawie identyczna z tym, co już zostało opublikowane.
maulinglawns
@maulinglawns, ta odpowiedź, w przeciwieństwie do innych, ma tę zaletę, że jest przenośna dla wszystkich powłok podobnych do Bourne'a (byłoby lepiej, gdyby błąd był wyprowadzany na stderr, status wyjścia był niezerowy i cytowano jednak podstawienie polecenia )
Stéphane Chazelas,