Jak stworzyć „jeśli nie prawdziwy warunek”?

317

Chciałbym, aby echopolecenie zostało wykonane, gdy cat /etc/passwd | grep "sysa"nie jest prawdziwe.

Co ja robię źle?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi
Sandra Schlichting
źródło
7
Czy !nie powinno być w nawiasach? tj.[ ! EXPR ]
acraig5075
7
@ acraig5075 jest poprawny w obu przypadkach, ale w tej instrukcji wcale nie jest potrzebne polecenie testowe (takie są nawiasy kwadratowe).
Charles Duffy

Odpowiedzi:

454

próbować

if ! grep -q sysa /etc/passwd ; then

grepzwraca, truejeśli znajdzie cel wyszukiwania, a falsejeśli nie.

Więc NIE false== true.

if Ocena w powłokach ma być bardzo elastyczna i wiele razy nie wymaga łańcuchów poleceń (jak napisałeś).

Patrząc na kod $( ... )w obecnej postaci, należy pochwalić użycie metody podstawienia cmd, ale zastanów się, co z tego wynika. Spróbuj echo $(cat /etc/passwd | grep "sysa")zobaczyć, co mam na myśli. Możesz pójść dalej, używając opcji -c(count), aby grep, a następnie zrobić to, if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenco działa, ale jest to raczej stara szkoła.

ALE, możesz użyć najnowszych funkcji powłoki (ocena arytmetyczna), takich jak

if ! (( $(grep -c "sysa" /etc/passwd) == 0 )) ; then ...`

co daje również korzyść z używania operatorów porównania opartych na c-lang ==,<,>,>=,<=,%i kilku innych.

W tym przypadku, według komentarza Orwellophile'a, ocena arytmetyczna może być jeszcze bardziej ograniczona

if ! (( $(grep -c "sysa" /etc/passwd) )) ; then ....

LUB

if (( ! $(grep -c "sysa" /etc/passwd) )) ; then ....

Wreszcie jest nagroda o nazwie Useless Use of Cat (UUOC). :-) Niektórzy skaczą w górę i w dół i płaczą gothca! Powiem tylko, że grepmoże przyjmować nazwę pliku na linii cmd, więc po co wywoływać dodatkowe procesy i konstrukcje rur, kiedy nie musisz? ;-)

Mam nadzieję, że to pomoże.

łobuz
źródło
1
To wszystko jest naprawdę głupie, od mojej odpowiedzi do znacznie trudniejszego (pytanie) [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd byłby bardziej prawidłowym sposobem wyszukiwania / etc / passwd przypadkowo - grep -vgdzie -v odwraca wyszukiwanie, jeśli chcesz aby uniknąć bałaganu ||
Orwellophile,
1
tak, cóż, rozwiązanie problemu jest najskuteczniejsze, a następnie odpowiedź na konkretne pytanie. Próbowałem odpowiedzieć na konkretne pytanie. Dziękuję za twoje pomysły. Powodzenia wszystkim.
shellter
1
nie wybierając odpowiedzi, bardzo mi się podobały. po prostu rzuciłbym poprawnie ograniczoną nazwę użytkownika, w przeciwnym razie, jeśli OP naprawdę wyszuka „sys” lub coś takiego, dostanie całkiem niespodziankę. jeszcze jeden na drogę? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile
1
Świetny! Z jakiegoś powodu polecenie „! Grep -qs ...” nie działało z / proc / mounts i próbowałem dowiedzieć się, czy na jądrze Raspbian 4.9 zamontowano regularnie upuszczany dysk USB. Ten wykonał robotę doskonale!
DocWeird,
33

Myślę, że można to uprościć w:

grep sysa /etc/passwd || {
    echo "ERROR - The user sysa could not be looked up"
    exit 2
}

lub w jednym wierszu poleceń

$ grep sysa /etc/passwd || { echo "ERROR - The user sysa could not be looked up"; exit 2; }

Rony
źródło
4
Fajnie, ale wolę odpowiedź pana shellera, ponieważ jest ona „udokumentowana”, jest bardziej „czytelna” intencja programisty.
0zkr PM
1
Podoba mi się ta wersja. A co z dodawaniem 1>&2na końcu echodo drukowania stderr?
Julien
2
@ 0zkrPM Ale wersja shelltera nie działa w powłoce Bourne'a. Dostaniesz!: not found
ceving
1
Unikaj przekierowania danych wyjściowych, używając 'greptego w ten sposób. -qtłumi wydajność.
tbc0
8

Co ja robię źle?

$(...)zawiera wartość , a nie status wyjścia, dlatego takie podejście jest błędne. Jednak w tym konkretnym przypadku to rzeczywiście działa, ponieważ sysazostanie wydrukowane, dzięki czemu instrukcja testowa się spełni. Jednak if ! [ $(true) ]; then echo false; fizawsze wydrukować false, ponieważ truekomenda nie pisze nic na standardowe wyjście (mimo że kod wyjścia jest równy 0). Dlatego należy go przeformułować if ! grep ...; then.

Alternatywą byłoby cat /etc/passwd | grep "sysa" || echo error. Edit: Jak Alex wskazał, kot ma sensu tutaj : grep "sysa" /etc/passwd || echo error.

Znalazłem inne odpowiedzi raczej mylące, mam nadzieję, że to komuś pomoże.

phil294
źródło
1

W systemach Unix, które go obsługują (wydaje się, że nie macOS):

if getent passwd "$username" >/dev/null; then
    printf 'User %s exists\n' "$username"
else
    printf 'User %s does not exist\n' "$username"
fi 

Ma to tę zaletę, że wysyła zapytanie do dowolnej usługi katalogowej, która może być używana (YP / NIS lub LDAP itp.) Oraz do lokalnego pliku bazy danych haseł.


Problem grep -q "$username" /etc/passwdpolega na tym, że daje fałszywie dodatni wynik, gdy nie ma takiego użytkownika, ale coś innego pasuje do wzorca. Może się to zdarzyć, jeśli w pliku znajduje się częściowe lub dokładne dopasowanie.

Na przykład w moim passwdpliku jest napis:

build:*:21:21:base and xenocara build:/var/empty:/bin/ksh

W ten sposób sprowokować ważny mecz na rzeczy, jak carai enocitd., Mimo że nie ma takich użytkowników na moim systemie.

Aby greprozwiązanie było poprawne, musisz poprawnie przeanalizować /etc/passwdplik:

if cut -d ':' -f 1 /etc/passwd | grep -qxF "$username"; then
    # found
else
    # not found
fi

... lub jakikolwiek inny podobny test w stosunku do pierwszego z :-delimowanych pól.

Kusalananda
źródło
@SDsolar bashW tym przypadku Twój kod prawdopodobnie nie jest wykonywany .
Kusalananda,
1

Oto przykładowa odpowiedź:

Aby upewnić się, że rejestratory danych są w trybie online, cronskrypt uruchamia się co 15 minut i wygląda następująco:

#!/bin/bash
#
if ! ping -c 1 SOLAR &>/dev/null
then
  echo "SUBJECT:  SOLAR is not responding to ping" | ssmtp abc@def.com
  echo "SOLAR is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "SOLAR is up"
fi
#
if ! ping -c 1 OUTSIDE &>/dev/null
then
  echo "SUBJECT:  OUTSIDE is not responding to ping" | ssmtp abc@def.com
  echo "OUTSIDE is not responding to ping" | ssmtp 4151112222@txt.att.com
else
  echo "OUTSIDE is up"
fi
#

... i tak dalej dla każdego rejestratora danych, który można zobaczyć w montażu na stronie http://www.SDsolarBlog.com/montage


FYI, używając &>/dev/nullprzekierowuje wszystkie dane wyjściowe polecenia, w tym błędy, do/dev/null

(Warunkowe wymaga tylko exit statusz pingpoleceniem)

Również FYI, zauważ, że ponieważ cronzadania działają, ponieważ rootnie ma potrzeby używania sudo pingw cronskrypcie.

SDsolar
źródło