Warunkowe bash: jak wyrażenia „i”? (jeśli [! -z $ VAR && -e $ VAR])


281

Chyba nie wiem, jak to zrobić ”i„ testy ”. Chciałem się upewnić, że istnieje argument, który działał dobrze [ -e $VAR ], ale okazuje się, że był również oceniany jako prawdziwy na pustym łańcuchu; których nie chcę.

Jak ja i je razem? A może jest jeszcze jeden test, który spełnia to, czego chcę?

Odpowiedzi:


532
if [ ! -z "$var" ] && [ -e "$var" ]; then
      # something ...
fi

9
To rozwiązanie działa nawet w powłokach ściśle zgodnych z POSIX, a zatem także w bash; Aby jednak w pełni skorzystać z „bashizmów”, patrz odpowiedź @ paxdiablo.
mklement0

2
Bardzo się cieszę, widząc to zalecane zamiast przestarzałe -a.
Charles Duffy

1
Znalazłem jeszcze jedno doskonałe i szczegółowe wyjaśnienie - stackoverflow.com/questions/3601515/…
valentt

70

Z strony bashpodręcznika:

[[ expression ]] - zwraca status 0 lub 1 w zależności od oceny wyrażenia warunkowego.

W przypadku wyrażeń jedną z opcji jest:

expression1 && expression2- prawdziwe, gdy oba expression1i expression2są prawdziwe.

Możesz więc andpołączyć je w następujący sposób ( -njest odwrotnie -z, abyśmy mogli się go pozbyć !):

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

Jednak nie sądzę, aby było to potrzebne w tym przypadku, -e xyzzyjest prawdą, jeśli xyzzy plik istnieje i może dość łatwo obsługiwać puste ciągi. Jeśli tego właśnie chcesz, to tak naprawdę nie potrzebujesz -zniepustego czeku:

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

Innymi słowy, po prostu użyj:

if [[ -e "$var" ]] ; then
    echo "'$var' exists"
fi

1
Możemy to skrócić za pomocą[[ -e "$var" ]] && echo "'$var' exists"
jaypal singh

1
Tak, jeśli jest to jedna linijka (jak w moim przykładzie). Nie zrobiłbym tego, gdyby blok warunkowy był znacznie bardziej złożony.
paxdiablo

w przypadku, gdy istnieje tylko jedno - może nawet jedno - polecenie, warto skorzystać z tego formularza, ponieważ jest on krótszy
śr.

9
if [ -n "$var" -a -e "$var" ]; then
    do something ...
fi

 


10
Ponieważ POSIXnie definiuje zachowanie [złożonych zestawów testów, powinniśmy unikać -alub -oz [. Przeczytałem to tutaj .
jaypal singh

2
@ jaypal-singh Masz rację, ale temat ma bashtag i nie wspomina o POSIX, więc zamieszczam tę wersję, która działa pod bashi kilka innych nowoczesnych powłok.
Slava Semushin,

2
Jeśli zakładasz użycie bashlub innych nowoczesnych powłok, jest nawet mniej powodów, aby polecać -a.
chepner

Nawet w przypadku bash sposób, w jaki zachowują się te testy, nie jest dobrze zdefiniowany we wszystkich przypadkach narożnych. Zastanów się [ "$var1" -o "$var2" ]; jeśli var1=(i var2=), to mamy test na -oto, czy nie jest pusty, a nie na jedno z nichvar1 czy var2jest pusty. Ten rodzaj dwuznaczności jest jedynym uzasadnionym powodem tego x$varidiomu we współczesnych (tj. Po latach 90.) testkomendach z poprawnym cytowaniem i ten idiom musi zginąć w ogniu.
Charles Duffy

4

Po prostu podaj swoją zmienną:

[ -e "$VAR" ]

To ocenia, [ -e "" ]czy $VARjest pusty.

Twoja wersja nie działa, ponieważ ocenia [ -e ]. Teraz w tym przypadku bash po prostu sprawdza, czy pojedynczy argument ( -e) jest niepustym łańcuchem.

Z strony podręcznika:

testuj i [oceniaj wyrażenia warunkowe przy użyciu zestawu reguł opartych na liczbie argumentów. ...

1 argument

Wyrażenie jest prawdziwe wtedy i tylko wtedy, gdy argument nie jest pusty.

(Ponadto to rozwiązanie ma dodatkową zaletę pracy z nazwami plików zawierającymi spacje)


1

Znalazłem odpowiedź. Dzięki za sugestie!

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

Jakieś komentarze na ten temat? Grep wydaje się nieefektywny dwa razy, ale działa ...

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.