Прості логічні оператори в Bash


256

У мене є пара змінних, і я хочу перевірити наступний стан (виписаний словами, а потім моя невдала спроба скриптового сценарію):

if varA EQUALS 1 AND ( varB EQUALS "t1" OR varB EQUALS "t2" ) then 

do something

done.

І в своїй невдалій спробі я придумав:

if (($varA == 1)) && ( (($varB == "t1")) || (($varC == "t2")) ); 
  then
    scale=0.05
  fi

Відповіді:


682

Те, що ви написали, насправді майже працює (працювало б, якби всі змінні були числами), але це зовсім не ідіоматичний спосіб.

  • (…)в круглих дужках вказується на нижню частину . Те, що знаходиться всередині них, не є виразом, як у багатьох інших мовах. Це список команд (подібно до зовнішніх дужок). Ці команди виконуються в окремому підпроцесі, тому будь-яке перенаправлення, призначення тощо, що виконуються всередині дужок, не має ефекту поза дужками.
    • З провідним знаком долара $(…)- це підміна команд : всередині дужок є команда, а вихід з команди використовується як частина командного рядка (після додаткових розширень, якщо заміна не знаходиться між подвійними лапками, але це вже інша історія ) .
  • { … }дужки схожі на дужки в тому, що вони групують команди, але вони впливають лише на аналіз, а не на групування. Програма x=2; { x=4; }; echo $xдрукує 4, тоді як x=2; (x=4); echo $xдрукує 2. (Також дужки вимагають пробілів навколо них та крапку з комою перед закриттям, тоді як дужки - це не просто синтаксис.)
    • З провідним знаком долара ${VAR}- це розширення параметра , що розширюється до значення змінної, з можливими додатковими перетвореннями.
  • ((…))подвійні дужки оточують арифметичну інструкцію , тобто обчислення цілих чисел, із синтаксисом, що нагадує інші мови програмування. Цей синтаксис використовується в основному для виконання завдань і в умовних умовах.
    • Цей же синтаксис використовується в арифметичних виразах $((…)), які розширюються до цілого значення виразу.
  • [[ … ]]подвійні дужки оточують умовні вирази . Умовні вирази здебільшого будуються на таких операторах , як -n $variableтестування, чи змінна порожня, і -e $fileтестування, чи існує файл. Є також оператори рядки рівності: "$string1" == "$string2"(остерігайтеся , що права частина являє собою шаблон, наприклад , [[ $foo == a* ]]тести , якщо $fooпочинається з під aчас [[ $foo == "a*" ]]випробування , якщо $fooточно a*), і знайомі !, &&і ||оператори заперечення, кон'юнкції і диз'юнкції, а також дужки для угруповання. Зауважте, що вам потрібен пробіл навколо кожного оператора (наприклад [[ "$x" == "$y" ]], ні [[ "$x"=="$y" ]]), а також пробіл або символ, як у ;внутрішніх, так і зовні дужках (наприклад [[ -n $foo ]], не[[-n $foo]]).
  • [ … ]одинарні дужки - це альтернативна форма умовних виразів з більшою кількістю примх (але старших і більш портативних). Не пишіть жодної зараз; почніть турбуватися про них, коли знайдете сценарії, які їх містять.

Це ідіоматичний спосіб написання тесту на баш:

if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then

Якщо вам потрібна портативність до інших оболонок, це був би спосіб (зверніть увагу на додаткове котирування та окремі набори дужок навколо кожного окремого тесту та використання традиційного =оператора, а не ==варіанту ksh / bash / zsh ):

if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then

31
Чудовий пост, резюме дужок просто ідеально.
KomodoDave

10
Краще використовувати ==порівняння порівняння від присвоєння змінної (що також є =)
Буде Шеппард

1
О, я мав на увазі одиночні (круглі) дужки, вибачте за плутанину. Учасники [[ $varA = 1 && ($varB = "t1" || $varC = "t2") ]]не починають підпроцес, хоча перша точка пункту прямо говорить: "Що всередині [круглих дужок] не є виразом, як у багатьох інших мовах" - але це, безумовно, є тут! Це, мабуть, очевидно для досвідченого баш-майстра, але навіть не для мене негайно. Плутанина може виникнути через те, що окремі дужки можуть використовуватися у ifвисловлюванні, а не у виразах всередині подвійних дужок.
Пітер - Відновіть Моніку

2
@ протагоніст ==насправді не «ідіоматичніший», ніж =. Вони мають те саме значення, але ==ksh варіант також доступний у bash та zsh, тоді як =є портативним. Не існує насправді жодної переваги у використанні ==, і це не працює в звичайному ш.
перестань бути злим"

2
@WillSheppard Існує вже багато інших відмінностей між порівнянням та призначенням: порівняння знаходиться у дужках, присвоєння немає; порівняння має пробіли навколо оператора, призначення не має; призначення має ім’я змінної зліва, порівняння лише рідко має щось схоже на ім’я змінної зліва, і ви можете і повинні ставити лапки в будь-якому випадку. Ви можете писати ==всередині [[ … ]], якщо хочете, але =має перевагу також працювати [ … ], тому рекомендую зовсім не вживатися у звичку користуватися ==.
перестань бути злим"

34

дуже близько

if [[ $varA -eq 1 ]] && [[ $varB == 't1' || $varC == 't2' ]]; 
  then 
    scale=0.05
  fi

повинен працювати.

розбиваючи його

[[ $varA -eq 1 ]] 

це ціле порівняння, де як

$varB == 't1'

- це порівняння рядків. в іншому випадку я просто групую порівняння правильно.

Подвійні квадратні дужки розмежовують умовний вираз. І, я вважаю, що це хороше читання з цього приводу: "(IBM) Demystify test, [, [[, ((і, якщо-тоді-ще")


Просто для впевненості: цитування в 't1'них непотрібне, правда? Тому що, на відміну від арифметичних вказівок у подвійних дужках, де t1була б змінна, t1у умовному виразі у подвійних дужках є просто буквальним рядком. Тобто, [[ $varB == 't1' ]]точно так само, як [[ $varB == t1 ]], правда?
Пітер - Відновіть Моніку

6

Дуже портативна версія (навіть для застарілої оболонки Bourne):

if [ "$varA" = 1 -a \( "$varB" = "t1" -o "$varB" = "t2" \) ]
then    do-something
fi

Це має додаткову якість виконання лише одного підпроцесу (що є процесом [), незалежно від смаку оболонки.

Замініть =на, -eqякщо змінні містять числові значення, наприклад

  • 3 -eq 03 правда, але
  • 3 = 03неправдиво. (рядкове порівняння)

3

Ось код для короткої версії оператора if-then-else:

( [ $a -eq 1 ] || [ $b -eq 2 ] ) && echo "ok" || echo "nok"

Зверніть увагу на наступне:

  1. ||і &&операнди всередині, якщо умова (тобто між круглими дужками) є логічними операндами (або / і)

  2. ||і &&операнди зовні, якщо умова означає тоді / інше

Практично в заяві сказано:

якщо (a = 1 або b = 2), тоді "ok" else "nok"


Парентез ( ... )створює підшлунок. Можливо, { ... }замість цього потрібно використовувати брекети . Будь-який стан, створений в підзаголовці, не буде видно у абонента.
Клінт Пахл

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