Яка різниця між подвійними та одинарними квадратними дужками в bash?


426

Я просто задумався, у чому саме різниця між ними

[[ $STRING != foo ]]

і

[ $STRING != foo ]

є, окрім того, що останній відповідає позіксам, зустрічається в sh, а перший є розширенням, знайденим у bash.


1
У випадку, якщо вам також було цікаво використовувати дужки взагалі, наприклад у контексті ifзаяви, дивіться mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D
Kev

також із Документів Ubuntu: wiki.ubuntu.com/…
radistao

Відповіді:


309

Існує кілька відмінностей. На мою думку, декілька найважливіших:

  1. [це вбудований в Баш та багатьох інших сучасних раковин. Вбудований [подібний до testдодаткової вимоги закриття ]. Вбудовані [і testімітують функціональність, /bin/[а /bin/testтакож їхні обмеження, щоб сценарії були сумісними назад. Оригінальні виконувані файли все ще існують здебільшого для відповідності POSIX та зворотної сумісності. Запуск команди type [в Bash вказує, що [за замовчуванням інтерпретується як вбудований. (Примітка: which [шукає виконувані файли на PATH і еквівалентно type -p [)
  2. [[не настільки сумісний, він не обов'язково працюватиме з будь-якими /bin/shточками. Так [[само сучасніший варіант Bash / Zsh / Ksh.
  3. Оскільки [[вбудований в оболонку і не має застарілих вимог, вам не потрібно турбуватися про розбиття слів на основі змінної IFS, щоб зіпсувати змінні, які оцінюються на рядок з пробілами. Тому вам не потрібно ставити змінну в подвійні лапки.

Здебільшого, решта - це лише якийсь приємний синтаксис. Щоб побачити більше відмінностей, рекомендую це посилання на відповідь на поширені запитання: Яка різниця між тестом, [та [[? . Насправді, якщо ви серйозно ставитесь до сценарію баш, я рекомендую прочитати цілі вікі , включаючи поширені запитання, підводні камені та керівництво. Тестовий розділ із посібника також пояснює ці відмінності, і чому автор (-и) вважають [[, що це кращий вибір, якщо вам не потрібно турбуватися про те, щоб бути портативним. Основні причини:

  1. Вам не доведеться турбуватися про цитування лівої частини тесту, щоб він насправді читався як змінна.
  2. Вам не доведеться бігти менше і більше, ніж < >зі зворотними косими рисами, щоб вони не оцінювалися як перенаправлення вводу, що може дійсно зіпсувати деякі речі, перезаписуючи файли. Це знову повертається до [[побудови. Якщо [(тест) є зовнішньою програмою, оболонка повинна зробити виняток у тому, як вона оцінює, <і >лише при /bin/testвиклику, що насправді не має сенсу.

5
Дякую, посилання на bash FAQ було те, що я шукав (не знав про цю сторінку, дякую).
0x89

2
Я редагував вашу публікацію з цією інформацією, але [і тест виконуються як вбудовані. Вбудовані були розроблені для заміни / bin / [та / bin / test, але вони також потребували відтворення обмежень бінарних файлів. Команда 'type [' підтверджує, що використовується вбудований файл. 'котрий [' шукає лише виконувані файли на PATH і еквівалентний 'type -P ['
klynch

133

Коротко:

[є баш Бульдін

[[] - це ключові слова

Ключові слова: Ключові слова дуже схожі на вбудовані, але головна відмінність полягає в тому, що до них застосовуються спеціальні правила розбору. Наприклад, [- це bash вбудований, тоді як [[це ключове слово bash. Вони обидва використовуються для тестування матеріалів, але оскільки [[це ключове слово, а не вбудований, він має переваги від декількох спеціальних правил аналізу, які полегшують його:

  $ [ a < b ]
 -bash: b: No such file or directory
  $ [[ a < b ]]

Перший приклад повертає помилку, оскільки bash намагається перенаправити файл b до команди [a]. Другий приклад насправді робить те, що ви від нього очікуєте. Символ <більше не має свого особливого значення оператора перенаправлення файлів.

Джерело: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments


3
[команда оболонки POSIX; його не потрібно вбудовувати. ]Це лише аргумент, який шукає ця команда, щоб синтаксис був збалансованим. Команда є синонімом, за testвинятком того, testщо не шукає закриття ].
Каз


81

Відмінності в поведінці

Деякі відмінності на Bash 4.3.11:

  • Розширення POSIX проти Bash:

  • регулярна команда проти магії

    • [ - це лише звичайна команда зі дивним іменем.

      ]це лише аргумент, [який запобігає використанню подальших аргументів.

      Ubuntu 16.04 насправді має виконуваний файл, який /usr/bin/[надається coreutils, але вбудована версія bash має перевагу.

      Ніщо не змінюється так, як Bash розбирає команду.

      Зокрема, <це перенаправлення &&та ||об'єднання декількох команд, ( )генерування підшаровок, якщо не уникнути \, і розширення слова відбувається як завжди.

    • [[ X ]]являє собою єдину конструкцію, яка робить Xмагічний аналіз. <, &&, ||І ()розглядаються спеціально, і правила розбиття на слова різні.

      Існують також подальші відмінності, як =і =~.

      У Bashese: [це вбудована команда та [[є ключовим словом: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && і ||

    • [[ 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 ]було б рівнозначно.


Як користуватися printf 'ab' | grep -Eq 'ab?'всередині if [ … ]?
meeDamian

1
@meeDamian if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi. []це команда так само, як grep. Можливо, ()ця команда не знадобиться. Я не впевнений: я додав її через |, залежить від того, як Bash розбирає речі. Якщо не було, |я впевнений, що ви можете просто написати if cmd arg arg; then.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

1
@meeDamian так, немає необхідності в ()ній не здається: stackoverflow.com/questions/8965509 / ...
Чіро Сантіллі新疆改造中心法轮功六四事件

1
Гарний список! Дивіться також: wiki.ubuntu.com/…
radistao

5

Одинарна дужка, тобто []оболонка POSIX, сумісна з тим, щоб укласти умовний вираз.

Подвійні дужки, тобто [[]]розширена (або розширена) версія стандартної версії POSIX, підтримується bash та іншими оболонками (zsh, ksh).

У БАШЕЄВ, для кількісного порівняння ми використовуємо eq, ne, ltі gt, з подвійними дужками для порівняння ми можемо використовувати ==, !=, <,і в >буквальному сенсі.

  • [є синонімом тестової команди. Навіть якщо він вбудований в оболонку, він створює новий процес.
  • [[ це нова вдосконалена його версія, яка є ключовим словом, а не програмою.

наприклад:

[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory 
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works

4

На основі швидкого читання відповідних розділів сторінки сторінки, головна відмінність полягає в тому, що оператори ==і !=збігаються з шаблоном, а не з буквальним рядком, а також, що існує =~оператор порівняння регулярних виразів.

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