Що таке синтаксис складної умови в оболонці?


11

Якщо ви хочете висловити наступний тест у оболонці (sh):

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

Поки що найкраще мені вдалося написати це:

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

Я не знаю, як скласти && та || з правильним пріоритетом. Гуглінг не дав мені жодної відповіді (підручники дають лише основні приклади, якщо такі є)

Який синтаксис поєднувати ці два, якщо в одне?


1
Будь-яка причина не використовувати ksh? Тоді для вашого початкового коду знадобиться лише ще одна дужка:if (( a == 1 && ( b == 1 || b == 2 ))); then :; fi
маніпулювання

Відповіді:


15

Зауважте, що [[ ]]немає ні в 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та \( \).


Мої сценарії мають #! / bin / sh shebang, а оболонка за замовчуванням - ksh . Чому б не використовувались?
Offirmo

2
@Offirmo Якщо ви оголосили свій скрипт як /bin/sh, неправильно писати сценарій за допомогою функцій, не ввімкнутих sh. Ви повинні знати, що kshНЕ sh, а скоріше суперсет sh. Якщо ви kshперенесите свій -but-progla-as- shскрипт у систему, де shне є символьним посиланням ksh, він може зламатися. Ви можете уникнути цієї проблеми, переконавшись, що ваш сценарій відповідає декларації.
jw013

Я думав, що встановлення / bin / sh як shebang змусить мої сценарії викликати через / bin / sh . Ви маєте на увазі, що моя оболонка за замовчуванням (ksh) ігнорує шебанг і інтерпретує його безпосередньо?
Offirmo

@Offirmo Ви маєте рацію: shebang of /bin/shwill call /bin/sh. Проблема /bin/shне приймає [[. Ви не можете використовувати [[або використовувати оболонку, яка приймає [[, наприклад ksh, як ваш шебанг.
jw013

2
Проблема полягає не в тому, що -a/ -oне підтримується деякими реалізаціями, а в тому, що це не є надійним для довільних аргументів. Можливо, [ "$a" = "$b" -o "$b" = "$c" ]не вдасться до значень типу $aяк !у багатьох [реалізаціях.
Стефан Шазелас

2

Я спробував деякий синтаксис і виявив це

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

працює.


1
це працює для версії bash вище 4.
Nikhil Mulley


0

Правильний спосіб зробити це просто shell:

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

Пояснення:

testтут виступає в дужках і -oяк логічний або Якщо ви логічний і всередині "круглих дужок", ви б використовували -a.

Більше про це можна прочитати тут

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.