Я читаю приклади 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.
(Команда тестування ідентична [])