Bash-Bedingungen: Wie werden Ausdrücke „und“? (wenn [! -z $ VAR && -e $ VAR])

281

Ich glaube, ich bin mir nicht sicher, wie ich "und" Tests durchführen soll. Ich wollte sicherstellen, dass ein Argument existiert, mit dem es gut funktioniert [ -e $VAR ], aber es stellte sich heraus, dass es auch für eine leere Zeichenfolge als wahr bewertet wurde. was ich nicht will.

Wie mache ich sie zusammen? Oder gibt es einen anderen unären Test, der das erreicht, was ich will?

atxdba
quelle

Antworten:

532
if [ ! -z "$var" ] && [ -e "$var" ]; then
      # something ...
fi
jaypal singh
quelle
9
Diese Lösung funktioniert auch in streng POSIX-konformen Shells und daher auch in bash; Um jedoch die "Bashismen" voll auszunutzen, lesen Sie die Antwort von @ paxdiablo.
mklement0
2
Sehr froh zu sehen, dass dies anstelle des Veralteten empfohlen wird -a.
Charles Duffy
1
Ich fand eine andere ausgezeichnete und detaillierte Erklärung - stackoverflow.com/questions/3601515/…
valentt
70

Aus der bashManpage:

[[ expression ]] - abhängig von der Auswertung des bedingten Ausdrucks einen Status von 0 oder 1 zurückgeben.

Und für Ausdrücke ist eine der Optionen:

expression1 && expression2- wahr, wenn beide expression1und expression2wahr sind.

Sie können andsie also wie folgt zusammenfügen ( -nist das Gegenteil von, -zdamit wir das loswerden können !):

if [[ -n "$var" && -e "$var" ]] ; then
    echo "'$var' is non-empty and the file exists"
fi

Ich denke jedoch nicht, dass es in diesem Fall benötigt wird, -e xyzzyist wahr, wenn die xyzzy Datei existiert und ganz einfach mit leeren Zeichenfolgen umgehen kann. Wenn Sie dies möchten, benötigen Sie den -znicht leeren Scheck nicht:

pax> VAR=xyzzy
pax> if [[ -e $VAR ]] ; then echo yes ; fi
pax> VAR=/tmp
pax> if [[ -e $VAR ]] ; then echo yes ; fi
yes

Mit anderen Worten, verwenden Sie einfach:

if [[ -e "$var" ]] ; then
    echo "'$var' exists"
fi
paxdiablo
quelle
1
Wir können es verkürzen mit[[ -e "$var" ]] && echo "'$var' exists"
Jaypal Singh
1
Ja, wenn es ein Einzeiler ist (wie mein Beispiel war). Ich würde das nicht tun, wenn der bedingte Block viel komplexer wäre.
Paxdiablo
Falls es nur einen - vielleicht sogar langen - Befehl gibt, ist es sinnvoll, dieses Formular zu verwenden, da es kürzer ist
avp
9
if [ -n "$var" -a -e "$var" ]; then
    do something ...
fi

 

Slava Semushin
quelle
10
Da POSIXdas Verhalten [bei komplexen Testreihen nicht definiert ist , sollten wir die Verwendung von -aoder -omit vermeiden [. Ich habe es hier gelesen .
Jaypal Singh
2
@ jaypal-singh Du hast recht, aber das Thema hat ein bashTag und keine Erwähnung über POSIX, also poste ich diese Version, die unter bashund einigen anderen modernen Shells funktioniert .
Slava Semushin
2
Wenn Sie die Verwendung bashoder anderer moderner Muscheln annehmen , gibt es noch weniger Gründe, dies zu empfehlen -a.
Chepner
Selbst mit Bash ist das Verhalten dieser Tests nicht in allen Eckfällen genau definiert. Betrachten Sie [ "$var1" -o "$var2" ]; Wenn var1=(und var2=), dann haben wir einen Test, ob -onicht leer ist, anstatt ob einer von var1oder var2nicht leer ist. Diese Art von Mehrdeutigkeit ist der einzige legitime Grund für die x$varRedewendung in modernen ( dh nach den 90er Jahren) testBefehlen mit korrekten Zitaten, und diese Redewendung muss in einem Feuer sterben.
Charles Duffy
4

Zitieren Sie einfach Ihre Variable:

[ -e "$VAR" ]

Dies ergibt , [ -e "" ]ob $VARleer ist.

Ihre Version funktioniert nicht, da sie ausgewertet wird [ -e ]. In diesem Fall prüft bash einfach, ob das einzelne Argument ( -e) eine nicht leere Zeichenfolge ist.

Aus der Manpage:

teste und [bewerte bedingte Ausdrücke anhand eines Regelsatzes, der auf der Anzahl der Argumente basiert. ...

1 Argument

Der Ausdruck ist genau dann wahr, wenn das Argument nicht null ist.

(Diese Lösung bietet außerdem den zusätzlichen Vorteil, dass Sie mit Dateinamen arbeiten können, die Leerzeichen enthalten.)

user123444555621
quelle
1

Ich habe jetzt eine Antwort gefunden. Vielen Dank für Ihre Vorschläge!

for e in ./*.cutoff.txt; do
if grep -q -E 'COX1|Cu-oxidase' $e
then
    echo xyz >$e.match.txt
else
    echo
fi

if grep -q -E 'AMO' $e
then
    echo abc >$e.match.txt
else
    echo
fi; done

Irgendwelche Kommentare dazu? Es scheint ineffizient zu sein, zweimal zu grepen, aber es funktioniert ...

rororo
quelle