Как представить несколько условий в оболочке, если заявление?

171

Я хочу представить несколько таких условий:

if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]   
then  
    echo abc;  
else  
    echo efg;   
fi  

но когда я выполняю script, он показывает

syntax error at line 15: `[' unexpected, 

где строка 15 - та, которая отображается, если....

Что не так с этим условием? Я думаю, что что-то не так с ().

  • 5
    Вы спрашиваете не об условиях оболочки, а об условиях тестирования . Все выражение в вашем примере оценивается с помощью test ( [ ), а не оболочки. Оболочка оценивает только состояние выхода [ .
  • 0
    Смотрите также stackoverflow.com/questions/16203088/…
Теги:

6 ответов

249
Лучший ответ

Классическая техника (метасимволы выхода):

if [ \( "$g" -eq 1 -a "$c" = "123" \) -o \( "$g" -eq 2 -a "$c" = "456" \) ]
then echo abc
else echo efg
fi

Я заключил ссылки на $g в двойных кавычках; что хорошая практика, в общем. Строго, скобки не нужны, потому что приоритет -a и -o делает его правильным даже без них.

Обратите внимание, что операторы -a и -o являются частью спецификации POSIX для test, aka [, в основном для обратной совместимости (поскольку они были частью test в 7-м выпуске UNIX, например), но они явно отмечены как "устаревшие" от POSIX. Bash (см. условные выражения), кажется, вытесняет классические значения и значения POSIX для -a и -o со своими альтернативными операторами, которые принимают аргументы.


С некоторой осторожностью вы можете использовать более современный оператор [[, но имейте в виду, что версии в Bash и Korn Shell (например) не обязательно должны быть идентичными.

for g in 1 2 3
do
    for c in 123 456 789
    do
        if [[ ( "$g" -eq 1 && "$c" = "123" ) || ( "$g" -eq 2 && "$c" = "456" ) ]]
        then echo "g = $g; c = $c; true"
        else echo "g = $g; c = $c; false"
        fi
    done
done

Пример выполнения, используя Bash 3.2.57 в Mac OS X:

g = 1; c = 123; true
g = 1; c = 456; false
g = 1; c = 789; false
g = 2; c = 123; false
g = 2; c = 456; true
g = 2; c = 789; false
g = 3; c = 123; false
g = 3; c = 456; false
g = 3; c = 789; false

Вам не нужно указывать переменные в [[, как и в случае с [, потому что это не отдельная команда так же, как [.


Разве это не классический вопрос?

Я бы так подумал. Однако есть и другая альтернатива:

if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ]
then echo abc
else echo efg
fi

В самом деле, если вы читаете руководство "переносимой оболочки" для инструмента autoconf или связанных пакетов, это обозначение - используя "||" и "&&" - это то, что они рекомендуют. Я полагаю, вы могли бы даже зайти так далеко, как:

if [ "$g" -eq 1 ] && [ "$c" = "123" ]
then echo abc
elif [ "$g" -eq 2 ] && [ "$c" = "456" ]
then echo abc
else echo efg
fi

Если действия такие же тривиальные, как эхо, это неплохо. Когда блок действия, который нужно повторить, является несколькими строками, повторение слишком болезненно, и одна из более ранних версий предпочтительнее - или вам нужно обернуть действия в функцию, которая вызывается в разных блоках then.

  • 0
    Большое спасибо, \ (работает. Почему я не нашел ответ на другом сайте? Разве это не классический вопрос?
  • 7
    Хорошо знать, что экранированные скобки работают; в качестве отступления: в данном конкретном случае скобки даже не нужны, потому что -a самом деле имеет более высокий приоритет, чем -o (в отличие от && и || в оболочке - однако внутри условных bash [[ ... ]] , && также имеет более высокий приоритет, чем || ). Если вы хотите избежать -a и -o для максимальной надежности и переносимости - что предлагает сама справочная страница POSIX - вы также можете использовать подгруппы для группировки: if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
Показать ещё 1 комментарий
107

В Bash:

if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]]
  • 7
    Определенно лучший подход в bash . В качестве отступления: в данном конкретном случае скобки даже не нужны, потому что внутри [[ ... ]] условные && самом деле имеют более высокий приоритет, чем || - в отличие от таких условностей.
  • 0
    Есть ли способ узнать, какое условие здесь соответствует? Это был первый в круглых скобках или другой?
Показать ещё 4 комментария
9

Используя /bin/bash, будет работать следующее:

if [ "$option" = "Y" ] || [ "$option" = "y" ]; then
    echo "Entered $option"
fi
5

Будьте осторожны, если у вас есть пробелы в строковых переменных, и вы проверяете существование. Обязательно укажите их правильно.

if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then
  • 1
    когда мы используем фигурные скобки после символа доллара !!
5
$ g=3
$ c=133
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
efg
$ g=1
$ c=123
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
abc
  • 1
    Это бесполезная подделка. { ;} можно использовать вместо
0
#!/bin/bash

current_usage=$( df -h | grep 'gfsvg-gfslv' | awk {'print $5'} )
echo $current_usage
critical_usage=6%
warning_usage=3%

if [ ${current_usage%?} -lt ${warning_usage%?} ]; then
echo OK current usage is $current_usage
elif [ ${current_usage%?} -ge ${warning_usage%?} ] && [ ${current_usage%?} -lt ${critical_usage%?} ]; then
echo Warning $current_usage
else
echo Critical $current_usage
fi
  • 3
    Добро пожаловать в стек переполнения! Этот вопрос ищет объяснение , а не просто рабочий код. Ваш ответ не дает понять вопрос, и может быть удален. Пожалуйста, измените, чтобы объяснить, что вызывает наблюдаемые симптомы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню