Wie mache ich eine "wenn nicht wahre Bedingung"?

317

Ich möchte den echoBefehl ausführen lassen, wenn er cat /etc/passwd | grep "sysa"nicht wahr ist.

Was mache ich falsch?

if ! [ $(cat /etc/passwd | grep "sysa") ]; then
        echo "ERROR - The user sysa could not be looked up"
        exit 2
fi
Sandra Schlichting
quelle
7
Sollte das !nicht in den Klammern sein? dh[ ! EXPR ]
acraig5075
7
@ acraig5075 es ist so oder so gültig, aber in dieser Anweisung ist überhaupt kein Testbefehl (wie die Klammern lauten) erforderlich.
Charles Duffy

Antworten:

454

Versuchen

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

grepGibt zurück, truewenn das Suchziel gefunden wird und falsewenn dies nicht der Fall ist.

Also NICHT false== true.

if Die Auswertung in Shells ist sehr flexibel und erfordert häufig keine Befehlsketten (wie Sie geschrieben haben).

Wenn Sie Ihren Code so betrachten, wie er ist, ist Ihre Verwendung der $( ... )Form der cmd-Substitution zu empfehlen, aber denken Sie darüber nach, was aus dem Prozess herauskommt. Versuche echo $(cat /etc/passwd | grep "sysa")zu sehen, was ich meine. Sie können das weiterführen, indem Sie die -cOption (count) verwenden, um zu grep und dann zu tun, if ! [ $(grep -c "sysa" /etc/passwd) -eq 0 ] ; thenwas funktioniert, aber eher altmodisch ist.

ABER Sie könnten die neuesten Shell-Funktionen (arithmetische Auswertung) wie verwenden

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

Dies bietet Ihnen auch den Vorteil, die c-lang-basierten Vergleichsoperatoren ==,<,>,>=,<=,%und möglicherweise einige andere zu verwenden.

In diesem Fall kann laut einem Kommentar von Orwellophile die arithmetische Bewertung noch weiter reduziert werden, wie z

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

ODER

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

Schließlich gibt es eine Auszeichnung namens Useless Use of Cat (UUOC). :-) Manche Leute springen auf und ab und weinen Gothca! Ich sage nur, dass grepein Dateiname in die cmd-Zeile aufgenommen werden kann. Warum also zusätzliche Prozesse und Pipe-Konstruktionen aufrufen, wenn dies nicht erforderlich ist? ;-);

Ich hoffe das hilft.

Shellter
quelle
1
Es ist wirklich alles ziemlich albern, von meiner Antwort auf eine viel schwierigere (Frage) [ stackoverflow.com/a/30400327/912236] grep "^$user:" /etc/passwd wäre übrigens die korrektere Art, / etc / passwd zu suchen - grep -vwobei -v die Suche umkehrt, wenn Sie möchten um das Durcheinander von || zu vermeiden
Orwellophile
1
Ja, es gibt eine Lösung, die ein Problem am effizientesten löst, und dann wird eine bestimmte Frage beantwortet. Ich habe versucht, die spezifische Frage zu beantworten. Vielen Dank für Ihre Ideen. Allen viel Glück.
Shellter
1
Ich habe Ihre Antworten nicht ausgewählt und sie sehr genossen. Ich würde gerade eine ordnungsgemäß begrenzte Überprüfung des Benutzernamens durchführen, sonst, wenn das OP wirklich nach "sys" oder so etwas sucht, wird er ziemlich überrascht sein. noch eine für die Straße? (( $( cat file | grep regex | wc -l ) ? 0 : 1 ))
Orwellophile
1
Großartig! Aus irgendeinem Grund funktionierte "! Grep -qs ..." nicht mit / proc / mounts und versuchte herauszufinden, ob ein regelmäßig fallengelassener USB-Datenträger auf dem Raspbian 4.9-Kernel gemountet war. Dieser hat den Job perfekt gemacht!
DocWeird
33

Ich denke, es kann vereinfacht werden in:

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

oder in einer einzelnen Befehlszeile

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

Rony
quelle
4
Schön, aber ich bevorzuge die Antwort von Mr. Shellter, weil sie "selbst dokumentiert" ist und die Absicht des Programmierers "lesbarer" ist.
0zkr PM
1
Ich mag diese Version. Was ist mit dem Hinzufügen 1>&2am Ende Ihres echoAusdrucks stderr?
Julien
2
@ 0zkrPM Aber die Shellter-Version funktioniert nicht in der Bourne-Shell. Sie erhalten!: not found
ceving
1
Vermeiden Sie die Ausgabeumleitung, wenn Sie 'grepdiese verwenden. -qunterdrückt die Ausgabe.
TBC0
8

Was mache ich falsch?

$(...)hält den Wert , nicht den Exit-Status, deshalb ist dieser Ansatz falsch. In diesem speziellen Fall funktioniert es jedoch tatsächlich, da sysaes gedruckt wird, wodurch die Testaussage wahr wird. Allerdings if ! [ $(true) ]; then echo false; fidrucken würde immer , falseweil der trueBefehl keine Schreib etwas zu stdout tut (auch wenn der Exit - Code 0). Deshalb muss es umformuliert werden if ! grep ...; then.

Eine Alternative wäre cat /etc/passwd | grep "sysa" || echo error. Edit: Wie Alex betonte, ist Katze hier nutzlos : grep "sysa" /etc/passwd || echo error.

Fanden die anderen Antworten eher verwirrend, hoffe das hilft jemandem.

phil294
quelle
1

Auf Unix-Systemen, die dies unterstützen (anscheinend nicht unter macOS):

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

Dies hat den Vorteil, dass alle möglicherweise verwendeten Verzeichnisdienste (YP / NIS oder LDAP usw.) und die lokale Kennwortdatenbankdatei abgefragt werden.


Das Problem dabei grep -q "$username" /etc/passwdist, dass es ein falsches Positiv gibt, wenn es keinen solchen Benutzer gibt, aber etwas anderes dem Muster entspricht. Dies kann passieren, wenn an einer anderen Stelle in der Datei eine teilweise oder genaue Übereinstimmung vorliegt.

In meiner passwdDatei steht beispielsweise eine Zeile mit der Aufschrift

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

Dies würde eine gültige Übereinstimmung für Dinge wie caraund enocusw. hervorrufen , obwohl es auf meinem System keine solchen Benutzer gibt.

Damit eine grepLösung korrekt ist, müssen Sie die /etc/passwdDatei ordnungsgemäß analysieren :

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

... oder einen ähnlichen Test gegen das erste der :begrenzten Felder.

Kusalananda
quelle
@SDsolar Ihr Code wird bashin diesem Fall wahrscheinlich nicht ausgeführt .
Kusalananda
1

Hier ist eine Antwort als Beispiel:

Um sicherzustellen, dass Datenlogger online sind, wird cronalle 15 Minuten ein Skript ausgeführt, das folgendermaßen aussieht:

#!/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
#

... und so weiter für jeden Datenlogger, den Sie in der Montage unter http://www.SDsolarBlog.com/montage sehen können


Zu Ihrer Information: &>/dev/nullLeitet alle Ausgaben des Befehls, einschließlich Fehler, an weiter/dev/null

(Die Bedingung erfordert nur exit statusden pingBefehl)

Auch FYI, beachten Sie, dass seit cronAufträge ausführen als rootes keine Notwendigkeit zu verwenden , ist sudo pingin einem cronSkript.

SDsolar
quelle