Simple logical operators in Bash
I have a couple of variables and I want to check the following condition (written out in words, then my failed attempt at bash scripting):
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
5 Answers 5
What you’ve written actually almost works (it would work if all the variables were numbers), but it’s not an idiomatic way at all.
- (…) parentheses indicate a subshell. What’s inside them isn’t an expression like in many other languages. It’s a list of commands (just like outside parentheses). These commands are executed in a separate subprocess, so any redirection, assignment, etc. performed inside the parentheses has no effect outside the parentheses.
- With a leading dollar sign, $(…) is a command substitution: there is a command inside the parentheses, and the output from the command is used as part of the command line (after extra expansions unless the substitution is between double quotes, but that’s another story).
- With a leading dollar sign, $ is a parameter expansion, expanding to the value of a variable, with possible extra transformations.
- The same syntax is used in arithmetic expressions $((…)) , which expand to the integer value of the expression.
This is the idiomatic way to write your test in bash:
If you need portability to other shells, this would be the way (note the additional quoting and the separate sets of brackets around each individual test, and the use of the traditional = operator rather than the ksh/bash/zsh == variant):
You could emphasize that single brackets have completely different semantics inside and outside of double brackets. (Because you start with explicitly pointing out the subshell semantics but then only as an aside mention the grouping semantics as part of conditional expressions. Was confusing to me for a second when I looked at your idiomatic example.)
Oh, I meant single (round) parentheses, sorry for the confusion. The ones in [[ $varA = 1 && ($varB = «t1» || $varC = «t2») ]] do not start a sub process although the first bullet point explicitly says: «What’s inside [parentheses] isn’t an expression like in many other languages» — but it certainly is here! That is probably obvious to the experienced bash wiz, but not even to me, immediately. The confusion can arise because single parentheses can be used in an if statement, just not in expressions inside double brackets.
@protagonist == is not really “more idiomatic” than = . They have the same meaning, but == is a ksh variant also available in bash and zsh, whereas = is portable. There isn’t really any advantage to using == , and it doesn’t work in plain sh.
@WillSheppard There are already many other differences between comparison and assignment: comparison is inside brackets, assignment is not; comparison has spaces around the operator, assignment doesn’t; assignment has a variable name on the left, comparison only rarely has something that looks like a variable name on the left and you can and should put quotes anyway. You can write == inside [[ … ]] , if you want but = has the advantage of also working in [ … ] , so I recommend not getting into the habit of using == at all.
Проверка условий в bash
Часто при написании скриптов под bash необходимо проверять результаты выполнения тех или иных команд.
Это немного подправленная выдержка из этой статьи .
Скобки
[ — является специальной встроенной командой test воспринимающей свои аргументы как выражение сравнения или файловую проверку […..].
[[ — расширенный вариант от «[«, является зарезервированным словом, а не командой, его bash выполняет как один элемент с кодом возврата. Внутри «[[….]]» разрешается выполнение операторов &&, || которые приводят к ошибке в обычных скобках «[….]» тем самым вариант с двойной скобкой более универсален.
(( — является арифметическими выражениями, которое так же возвращают код 0. Тем самым такие выражения могут участвовать в операциях сравнения.
Приведу список логических операторов, которые используются для if|then|else:
-z – строка пуста
-n – строка не пуста
=, ( == ) – строки равны
!= – строки неравны
-ne – неравно
-gt,(>) – больше
-ge,(>=) — больше или равно
! — отрицание логического выражения
-a,(&&) – логическое «И»
-o,(||) -логическое «ИЛИ»
Конструкции простой проверки if|then
if [[ condition ]]; then commands fi
Другими словами:
если проверяемое_выражение_или_команды_верны; то выполняем команды закрываем если
#!/bin/bash if echo Тест; then echo 0 fi
Часто встречается в скриптах проверка — «существует ли файлы или каталоги» на их примере покажу работу
#!/bin/bash if [ -f $HOME/.bashrc ]; then echo "Файл существует!" fi
$HOME/.bashrc – путь до файла
echo – печатает сообщение в консоль#!/bin/bash if [[ -f $HOME/.bashrc && -f /usr/bin/nano ]]; then echo "Все впорядке, можно редактировать!" fi
&& — логическое «и», если первый путь «истина» проверяем второй, если он тоже «истина», то выполняем команды (echo)
-f – ключ проверки на существования файла (о них чуть ниже)Конструкции простой проверки if|then|else
if [[ condition ]]; then commands 1 else commands 2 fi
если проверяемое_выражение_или_команды_верны; то команды 1 иначе команды 2 закрываем если
Возможно не лучший пример, нас интересует именно ответ 0 или 1. В результате печатается в консоль «Тест» и «0» потому что команда «echo Тест» успешна и это «истина».
#!/bin/bash if echo Тест; then echo 0 else echo 1 fi
Намерено допустите ошибку изменив echo, в результате получите «1» и сообщение о том что «команда echo не существует» и это «ложь».
#!/bin/bash if echo Тест; then echo 0 else echo 1 fi
Примеры «существуют ли файл?»
Если файл bashrc существует, то печатает в консоль «Файл существует!», иначе печатает «Файл не существует!»
#!/bin/bash if [ -f "$HOME/.bashrc" ]; then echo "Файл существует!" else echo "Файл не существует!" fi
Поиграйте с именем проверяемого файла
#!/bin/bash if [[ -f "$HOME/.bashrc" && -f "/usr/bin/nano" ]]; then echo "Все в порядке, можно редактировать!" else echo "Ошибка!" fi
Ключи к файлам и каталогам
[ -ключ “путь” ]
[ -e “путь каталогу_или_файлу”] – существует ли файл или каталог.[ -r “путь к файлу/каталогу”] – доступен ли файл/каталог для чтения.
[ -f “путь к файлу/каталогу”] – существует ли файл.
[ -d “путь к каталогу”] – существует ли каталог.
Полное описание возможных применений различных скобок, правильное расставление кавычек уходит далеко от темы, поэтому могу посоветовать обратится к руководству Advanced Bash ScriptingАрифметика
Если оператор > использовать внутри [[….]], он рассматривается как оператор сравнения строк, а не чисел. Поэтому операторам > и < для сравнения чисел лучше заключить в круглые скобки.
Используем круглые скобки для математического сравнение. Если «3» меньше «6» печатаем «Да».
#!/bin/bash if (( 3 6));then echo Да fi
Использование команды test, коей являются квадратные скобки. Если «3» меньше «6» печатаем «Да».
#!/bin/bash if [ 3 -lt 6 ]; then echo Да fi
Можно использовать и двойные квадратные скобки, это расширенный вариант команды test, эквивалентом которой является «[ ]». Если «3» меньше «6» печатаем «Да».
#!/bin/bash if [[ 3 -lt 6 ]]; then echo Да fi
Используем двойные квадратные скобки, потому что применяем оператор «&&». Если первое выражение 2 = 2 (истина) тогда выполняем второе, и если оно тоже 2=2 (истина), печатаем «Верно»
#!/bin/bash a="2" b="2" if [[ 2 = "$a" && 2 = "$b" ]] ; then echo Верно else echo Не верно fi
Если первое выражение 2 = 2 (истина) тогда выполняем второе, и если переменная «b» не равна двум (ложь), печатаем «Не верно»
#!/bin/bash a="2" b="3" if [[ 2 = "$a" && 2 = "$b" ]] ; then echo Верно else echo Не верно fi
Можно конечно сделать проще, нам главное понять принцип if|then и else, не стесняйтесь менять, подставляя свои значения.
Вложение нескольких проверок
Bash позволяет вкладывать в блок несколько блоков
#!/bin/bash if [[ condition 1 ]]; then if [[ condition 2 ]]; then command 1 else command 2 fi else command 3 fi
Построения многоярусных конструкций
Для построения многоярусных конструкции, когда необходимо выполнять множество проверок лучше использовать elif — это краткая форма записи конструкции else if.
if [[ condition 1 ]]; then command 1 command 2 elif [[ condition 2 ]]; then command 3 command 4 else command 5 fi
Linux bash логические операторы
Запись: xintrea/mytetra_db_mcold/master/base/150167745286rzblv9si/text.html на raw.githubusercontent.com
В bash есть много операторов для описания условных выражений и логических операций и их синтаксис не всегда привычен (по крайней мере на первый взгляд), так что не лишним будет иметь шпаргалку.
Элементарные условные выражения для файлов:
- -e — файл существует;
- -f — обычный файл (не каталог и не файл устройства);
- -s — ненулевой размер файла;
- -d — файл является каталогом;
- -b — файл является блочным устройством (floppy, cdrom и т.п.);
- -c — файл является символьным устройством (клавиатура, модем, звуковая карта и т.п.);
- -p — файл является каналом;
- -h — файл является символической ссылкой;
- -L — файл является символической ссылкой;
- -S — файл является сокетом;
- -t — файл связан с терминальным устройством;
- -r — файл доступен для чтения (пользователю, запустившему сценарий);
- -w — файл доступен для записи (пользователю, запустившему сценарий);
- -x — файл доступен для исполнения (пользователю, запустившему сценарий);
- -g — (sgid) флаг для файла или каталога установлен;
- -u — (suid) флаг для файла установлен;
- -k — флаг sticky bit установлен;
- -O — вы являетесь владельцем файла (пользователь запустивший сценарий);
- -G — вы принадлежите к той же группе, что и файл (пользователь запустивший сценарий);
- -N — файл был модифицирован с момента последнего чтения;
- file1 -nt file2 – file1 более новый, чем file2;
- file1 -ot file2 – file1 более старый, чем file2;
- file1 -ef file2 – file1 и file2 являются «жесткими» ссылками на один и тот же файл.
Элементарные условные выражение для сравнения строк:
- -z str – длина строки str равна 0;
- -n str – длина строки str не равно 0;
- str1 == str2 или str1 = str2 – строки совпадают;
- str1 !== str2 или str1 != str2 – строки не совпадают;
- str1 < str2 – str1 предшествует str2 в лексикографическом порядке;
- str1 > str2 – str1 следует за str2 в лексикографическом порядке.
Арифметическое условное выражение имеет формат: arg1 операция arg2, где аргументами являются целые числа, и допустимы следующие операции:
- -eq – равно;
- -ne – не равно;
- -lt – меньше;
- -le – меньше или равно;
- -gt – больше;
- -ge – больше или равно;
- < — меньше (внутри двойных круглых скобок);
- > — больше (внутри двойных круглых скобок);
- >= — больше или равно (внутри двойных круглых скобок);
Команды возвращающие код возврата (звучит странно, но команды нужные):
- test — используется для логического сравнения (например test -f /home/kyrych/readme вернет истину если readme — обычный файл);
- [ ] — является специальной встроенной командой воспринимающей свои аргументы как выражение сравнения или файловую проверку [. ]. Вызывает ошибку при попытке использования внутри || (логическое или) и & (логическое и);
- [[ ]] — расширенная версия «[» (начиная с версии 2.02), внутри которой могут быть использованы || (логическое или), & (логическое и). Должна иметь закрывающую скобку «]]» (является зарезервированным словом, а не командой, его bash выполняет как один элемент с кодом возврата)
- (( )) — математическое сравнение.