Каков синтаксис сложного условия в оболочке?

10

Если хотите выразить следующий тест в shell (sh):

if ( a == 1 && ( b == 1 || b == 2 )) { ... }

На данный момент лучшее, что я смог написать, это:

if [[ $a -eq 1 ]]; then
  if [[ $b -eq 1 || $b -eq 2 ]]; then
     ...
  fi
fi

Я не знаю, как составить && и || с правильным приоритетом. Поиск в Google не дал мне никакого ответа (учебники дают только основные примеры, если таковые имеются)

Какой синтаксис объединить эти два, если в один?

Offirmo
источник
1
Любая причина не использовать ksh? Тогда ваш исходный код потребует только еще одну пару круглых скобок:if (( a == 1 && ( b == 1 || b == 2 ))); then :; fi
manatwork

Ответы:

14

Обратите внимание, что [[ ]]нет ни в Bourne, ни в POSIX sh. Для истинного shсинтаксиса, есть несколько способов сделать это.

Используя только одну [ ]пару

if [ 1 -eq "$a" -a \( 1 -eq "$b" -o 2 -eq "$b" \) ]; then
    # ...
fi

или Избегая POSIX -aи -oвариантов 1

if [ 1 -eq "$a" ] && { [ 1 -eq "$b" ] || [ 2 -eq "$b" ]; }; then
    # ...
fi

1 Одной из причин для предотвращения -aи -oмаксимально портативность - не все testили [реализации могут обрабатывать более 4 аргумента, который является именно то , что вы получите , если вы цепь выражений с -aи -oи \( \).

jw013
источник
Мои скрипты имеют #! / bin / sh shebang, и оболочкой по умолчанию является ksh . Почему бы не использовать sh?
Offirmo
2
@Offirmo Если вы объявите свой скрипт как /bin/sh, неправильно писать скрипт, используя функции, отсутствующие в sh. Вы должны знать, что kshэто НЕ sh, а скорее надмножество sh. Если вы kshперенесете свой -but-объявленный-как- shскрипт в систему, где shнет символической ссылки ksh, он может сломаться. Вы можете избежать этой проблемы, убедившись, что ваш скрипт соответствует объявлению.
jw013
Я думал, что установка / bin / sh как shebang заставит мои скрипты вызываться через / bin / sh . Вы имеете в виду, что моя оболочка по умолчанию (ksh) игнорирует шебанг и интерпретирует его напрямую?
Offirmo
@Offirmo Вы правы: шебанг /bin/shвызовет /bin/sh. Проблема /bin/shне принимает [[. Вы можете либо не использовать, [[либо использовать оболочку, которая принимает [[, например ksh, как ваш шебанг.
jw013
2
Проблема заключается не в том , что многое , что -a/ -oне поддерживаются некоторыми реализациями но это не является надежным для произвольных аргументов. Как [ "$a" = "$b" -o "$b" = "$c" ]и в случае со значениями типа $aLike !во многих [реализациях.
Стефан Шазелас
2

Я попробовал некоторый синтаксис и обнаружил, что

if [[ $a -eq 1 ]] && [[ $b -eq 1 || $b -eq 2 ]]; then
 ...
fi

работает.

Offirmo
источник
1
это работает для bash версии выше 4.
Nikhil Mulley
2

Другой подход POSIX:

if [ "$((a == 1 && ( b == 1 || b == 2 )))" -ne 0 ]; then
  ...
fi
Стефан Шазелас
источник
0

Правильный способ сделать это с помощью простого shell:

if test 1 -eq "$a" && test 1 -eq "$b" -o 2 -eq "$b"; then 
    ...
fi

Объяснение:

testздесь служит в качестве скобок и -oкак логический или. Если вы логичны и внутри «скобок» вы бы воспользовались -a.

Подробнее об этом можно узнать здесь

Омер Даган
источник