Условные выражения Bash: как выразить «и»? (если [! -z $ VAR && -e $ VAR])

281

Я думаю, что я не понимаю, как делать "и" тесты. Я хотел убедиться, что существовал аргумент, который хорошо работал [ -e $VAR ], но оказалось, что он также оценивался как true для пустой строки; который я не хочу.

Как мне «и» их вместе? Или есть другой унарный тест, который выполняет то, что я хочу?

atxdba
источник

Ответы:

532
if [ ! -z "$var" ] && [ -e "$var" ]; then
      # something ...
fi
Джайпал Сингх
источник
9
Это решение работает даже в строго POSIX-совместимых оболочках и, следовательно, также в bash; однако, чтобы в полной мере воспользоваться "bashisms", см. ответ @ paxdiablo.
mklement0
2
Очень рад видеть это посоветованным вместо устаревшего -a.
Чарльз Даффи
1
Я нашел еще одно отличное и подробное объяснение - stackoverflow.com/questions/3601515/…
valentt
70

Из bashсправочной страницы:

[[ expression ]] - вернуть состояние 0 или 1 в зависимости от оценки выражения условного выражения.

И, для выражений, один из вариантов:

expression1 && expression2- верно, если оба expression1и expression2верны.

Таким образом, вы можете andих вместе следующим образом ( -nэто противоположность, -zчтобы мы могли избавиться от !):

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

Тем не менее, я не думаю, что это необходимо в этом случае, -e xyzzyверно, если xyzzy файл существует и может довольно легко обрабатывать пустые строки. Если это то, что вы хотите, то вам на самом деле не нужна -zнепустая проверка:

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

Другими словами, просто используйте:

if [[ -e "$var" ]] ; then
    echo "'$var' exists"
fi
paxdiablo
источник
1
Мы можем сократить это с[[ -e "$var" ]] && echo "'$var' exists"
Jaypal Сингх
1
Да, если это однострочник (как мой пример). Я бы не стал этого делать, если бы условный блок был намного сложнее.
paxdiablo
в случае, если есть только одна, может быть, даже длинная команда, имеет смысл использовать эту форму, поскольку она короче
avp
9
if [ -n "$var" -a -e "$var" ]; then
    do something ...
fi

 

Слава Семушин
источник
10
Поскольку POSIXне определяет поведение [сложных наборов тестов, мы должны избегать использования -aили -oс [. Я читаю это здесь .
Джайпал Сингх
2
@ jaypal-singh Вы правы, но в теме есть bashтег, а не упоминание о POSIX, поэтому я выкладываю эту версию, которая работает под bashнекоторыми другими современными оболочками.
Слава Семушин
2
Если вы предполагаете использовать bashили другие современные снаряды, есть еще меньше причин рекомендовать -a.
chepner
Даже при использовании bash поведение этих тестов не всегда четко определено. Рассмотреть [ "$var1" -o "$var2" ]; если var1=(и var2=), то то, что у нас есть, является проверкой того, -oявляется ли оно не пустым, а не является ли оно пустым var1или var2нет. Такая двусмысленность - единственная законная причина для x$varидиомы в современных (то есть, после 90-х) testкомандах с правильным цитированием, и эта идиома должна погибнуть в огне.
Чарльз Даффи
4

Просто укажите свою переменную:

[ -e "$VAR" ]

Это оценивает, [ -e "" ]если $VARпусто.

Ваша версия не работает, потому что она оценивает [ -e ]. Теперь в этом случае bash просто проверяет, является ли единственный аргумент ( -e) непустой строкой.

Из справочной страницы:

проверить и [оценить условные выражения, используя набор правил, основанных на количестве аргументов. ...

1 аргумент

Выражение истинно тогда и только тогда, когда аргумент не равен нулю.

(Кроме того, это решение имеет дополнительное преимущество работы с именами файлов, содержащими пробелы)

user123444555621
источник
1

Я нашел ответ сейчас. Спасибо за ваши предложения!

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

Есть какие-нибудь комментарии по этому поводу? Кажется неэффективным grep дважды, но это работает ...

rororo
источник