Я читаю приклади bash, ifале деякі приклади написані з одинарними квадратними дужками:
if [ -f $param ]
then
#...
fi
інші з подвійними квадратними дужками:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Яка різниця?
Я читаю приклади bash, ifале деякі приклади написані з одинарними квадратними дужками:
if [ -f $param ]
then
#...
fi
інші з подвійними квадратними дужками:
if [[ $? -ne 0 ]]
then
start looking for errors in yourlog
fi
Яка різниця?
Відповіді:
Одиничні - []це випробування на відповідність оболонці пози.
Подвійні [[]]є розширенням до стандарту []і підтримуються bash та іншими оболонками (наприклад, zsh, ksh). Вони підтримують додаткові операції (як і стандартні операції посівок). Наприклад: ||замість -oі регулярного вирівнювання з =~. Більш повний перелік відмінностей можна знайти в розділі керівництва Баша про умовні конструкції .
Використовуйте, []коли хочете, щоб ваш скрипт переносився через оболонки. Використовуйте, [[]]якщо ви хочете, щоб умовні вирази не підтримувалися []і не потребували переносності.
[[ ]](наприклад, bash з #!/bin/bashабо #!/usr/bin/env bash), ви повинні використовувати переносний варіант. Сценарії, які передбачають, що / bin / sh підтримує розширення на зразок цього, зламається на таких ОС, як недавні випуски Debian і Ubuntu, де це не так.
Відмінності в поведінці
Тестовано на Bash 4.3.11:
Розширення POSIX проти Bash:
[ є POSIX[[є розширенням Bash¹, задокументованим за адресою: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructsрегулярна команда проти магії
[ - це лише звичайна команда зі дивним іменем.
]це лише аргумент, [який запобігає використанню подальших аргументів.
Ubuntu 16.04 насправді має виконуваний файл, який /usr/bin/[надається coreutils, але вбудована версія bash має перевагу.
Ніщо не змінюється так, як Bash розбирає команду.
Зокрема, <це перенаправлення &&та ||об'єднання декількох команд, ( )генерування підшаровок, якщо не уникнути \, і розширення слова відбувається як завжди.
[[ X ]]являє собою єдину конструкцію, яка робить Xмагічний розбір. <, &&, ||І ()розглядаються спеціально, і правила розбиття на слова різні.
Існують також подальші відмінності, як =і =~.
У Bashese: [це вбудована команда та [[є ключовим словом: /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]: лексикографічне порівняння[ a \< b ]: Так само, як вище. \потрібно або інакше робить перенаправлення, як і для будь-якої іншої команди. Розширення Bash.expr a \< b > /dev/null: POSIX еквівалент², див.: Як перевірити рядки на лексикографічну меншу чи рівну величину в Bash?&& і ||
[[ a = a && b = b ]]: вірно, логічно і[ a = a && b = b ]: помилка синтаксису, &&аналізується як роздільник команд ANDcmd1 && cmd2 [ a = a -a b = b ]: еквівалент, але застарілий POSIX³[ a = a ] && [ b = b ]: POSIX та надійний еквівалент(
[[ (a = a || a = b) && a = b ]]: помилковий[ ( a = a ) ]: синтаксична помилка, ()інтерпретується як піддіаграма[ \( a = a -o a = b \) -a a = b ]: еквівалент, але ()застаріло через POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]POSIX еквівалент 5розщеплення слів і генерація імен файлів у розширеннях (split + glob)
x='a b'; [[ $x = 'a b' ]]: правда, цитати не потрібніx='a b'; [ $x = 'a b' ]: синтаксична помилка, поширюється на [ a b = 'a b' ]x='*'; [ $x = 'a b' ]: помилка синтаксису, якщо в поточному каталозі є більше одного файлу.x='a b'; [ "$x" = 'a b' ]: POSIX еквівалент=
[[ ab = a? ]]: вірно, тому що воно відповідає узорності ( * ? [є магією). Не поширюється на файли у поточному каталозі.[ ab = a? ]: a?глобус розширюється. Так може бути правдою чи помилкою залежно від файлів у поточному каталозі.[ ab = a\? ]: хибне, а не глобальне розширення=і ==однакові в обох [і [[, але ==є розширенням Bash.case ab in (a?) echo match; esac: POSIX еквівалент[[ ab =~ 'ab?' ]]: false 4 , втрачає магію с''[[ ab? =~ 'ab?' ]]: правда=~
[[ ab =~ ab? ]]: вірно, POSIX розширений матч регулярного вираження , ?не розширюється глобально[ a =~ a ]: синтаксична помилка. Немає еквіваленту баш.printf 'ab\n' | grep -Eq 'ab?': POSIX-еквівалент (лише дані для одного рядка)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX еквівалент.Рекомендація : завжди використовуйте [].
Існують POSIX-еквіваленти для кожної [[ ]]конструкції, яку я бачив.
Якщо ви використовуєте [[ ]]:
[це лише звичайна команда зі дивним іменем, ніякої спеціальної семантики не задіяно.¹ Натхненний еквівалентною [[...]]конструкцією в оболонці Корна
², але не вдається для деяких значень aабо b(як +або index) і робить числове порівняння, якщо aі bвиглядає як десяткові цілі числа. expr "x$a" '<' "x$b"працює навколо обох.
³, а також не відповідає деяким значенням aабо bподібним !або (.
4 в bash 3.2 і вище і за умови сумісності з bash 3.1 не ввімкнено (наприклад, з BASH_COMPAT=3.1)
5 , хоча угруповання (тут з {...;}командою групою замість (...)якої буде працювати непотрібну подоболочкі) не є необхідним , як ||і &&оболонками операторів (на відміну від ||і && [[...]]операторів або -o/ -a [операторів) має однаковий пріоритет. Так [ a = a ] || [ a = b ] && [ a = b ]було б рівнозначно.
[] слід читати як " Мої переваги" : використовуйте, []якщо ви не хочете втрачати портативність . Як зазначено тут : Якщо переносимість / відповідність POSIX або BourneShell викликає занепокоєння, слід використовувати старий синтаксис. Якщо, з іншого боку, сценарій вимагає BASH, Zsh або KornShell, новий синтаксис, як правило, є більш гнучким, але необов'язково сумісним назад. Я вважаю за краще піти, [[ ab =~ ab? ]]якщо я можу і не буду хвилюватися щодо зворотної сумісності, ніжprintf 'ab' | grep -Eq 'ab?'
Всередині одинарних дужок для перевірки стану (тобто [...]) деякі оператори, такі як сингл =, підтримуються усіма оболонками, тоді як використання оператора ==не підтримується деякими старими оболонками.
Всередині подвійних дужок для перевірки стану (тобто [[...]]) немає різниці між використанням =або ==в старих або нових оболонках.
Редагувати: Я також повинен зазначити, що: У баші завжди використовуйте подвійні дужки [[...]], якщо можливо, тому що це безпечніше, ніж одинарні дужки. Я проілюструю, чому на наступному прикладі:
if [ $var == "hello" ]; then
якщо $ var стане нульовим / порожнім, то це те, що бачить сценарій:
if [ == "hello" ]; then
що порушить ваш сценарій. Рішення - або використовувати подвійні дужки, або завжди пам'ятати, щоб ставити лапки навколо змінних ( "$var"). Подвійні дужки є кращою оборонною практикою кодування.
[[- це ключове слово bash, схоже на (але більш потужне, ніж) [команду.
Побачити
http://mywiki.wooledge.org/BashFAQ/031 та http://mywiki.wooledge.org/BashGuide/TestsAndConditionss
Якщо ви не пишете для POSIX sh, ми рекомендуємо [[.
ви можете використовувати подвійні квадратні дужки для зіставлення легких регулярних виразів, наприклад:
if [[ $1 =~ "foo.*bar" ]] ; then
(поки версія bash, яку ви використовуєте, підтримує цей синтаксис)
Посібник Баша говорить:
При використанні з [[, оператори '<' та '>' сортують лексикографічно, використовуючи поточну локаль. Команда тесту використовує впорядкування ASCII.
(Команда тестування ідентична [])