Яка різниця між [[$ a == z *]] і [$ a == z *]?


35

Чи є різниця між цими двома.

[[ $a == z* ]]

і

[ $a == z* ] 

Чи можу я мати приклад, коли вони мали б різні результати?

Крім того, чим [[ ]]відрізняється робота [ ]?

Відповіді:


41

Різниця між [[ … ]]і [ … ]в основному покривається у використанні одинарного або подвійного дужок - bash . Принципово важливим [[ … ]]є спеціальний синтаксис, тоді як [команда - смішна на вигляд назва. [[ … ]]має спеціальні правила синтаксису для того, що знаходиться всередині, [ … ]не має.

З доданою зморшкою підстановки, ось як [[ $a == z* ]]оцінюється:

  1. Розбираємо команду: це [[ … ]]умовна конструкція навколо умовного виразу $a == z*.
  2. Розбираємо умовний вираз: це ==двійковий оператор, з операндами $aта z*.
  3. Розгорніть перший операнд на значення змінної a.
  4. Оцініть ==оператора: перевірити, чи відповідає значення змінної aшаблону z*.
  5. Оцініть умовний вираз: його результат - результат умовного оператора.
  6. Тепер команда оцінюється, її статус дорівнює 0, якщо умовний вираз був істинним і 1, якщо він був помилковим.

Ось як [ $a == z* ]оцінюється:

  1. Розбираємо команди: це [команда з аргументами , утворених оцінки слова $a, ==, z*, ].
  2. Розгорніть $aна значення змінної a.
  3. Виконайте розділення слів та створення імен файлів за параметрами команди.
    • Наприклад, якщо значення aє рядок 6 символів foo b*(отримана , наприклад a='foo b*') , і список файлів в поточному каталозі ( bar, baz, qux, zim, zum), то результат розкладання є наступним списком слів: [, foo, bar, baz, ==, zim, zum, ].
  4. Виконайте команду [з параметрами, отриманими на попередньому кроці.
    • З наведеними вище прикладами, [команда скаржиться на синтаксичну помилку і повертає статус 2.

Примітка. На [[ $a == z* ]]етапі 3 значення aне зазнає розщеплення слів та створення імені файлів, оскільки воно знаходиться в контексті, коли очікується одне слово (лівий аргумент умовного оператора ==). У більшості випадків, якщо одне слово має сенс на цій позиції, то змінне розширення веде себе так, як це відбувається у подвійних лапках. Однак є виняток із цього правила: у [[ abc == $a ]]випадку, якщо значення aмістить символи підстановки, aвоно співпадає з шаблоном підстановки. Наприклад, якщо значення aє a*те [[ abc == $a ]]істинно (бо підстановлювальний *виходячи з котирувального розширення $aматчів *) , тоді як [[ abc == "$a" ]]помилково (так як звичайний символ*що походить від цитованого розширення $aне відповідає bc). Всередині [[ … ]], подвійні лапки не роблять різниці, крім як на правій стороні операторів рядки відповідності ( =, ==, !=і =~).


39

[- псевдонім для testкоманди. У Unix версії 6 була ifкоманда, але версія 7 (1979) оснащена новою оболонкою Bourne, яка мала декілька програм програмування, включаючи конструкцію if-then-else-elif-fi, а Unix версія 7 додала testкоманду, яка виконувала більшу частину "тести", які були виконані ifкомандою у старих версіях.

[було створено псевдонім до testобох, і було вбудовано в оболонку в Unix System III (1981) . Хоча слід зауважити, що деякі варіанти Unix не мали [команди ще набагато пізніше після цього ( до початку 2000-х років на деяких BSD, де shбазується на оболонці Almquist ( testвбудований модуль завжди включався в ashджерело, але на ці BSD її спочатку було відключено)).

Зауважте, що testака [- це команда робити "тести", це завдання не виконується, тому немає ніяких причин розрізняти призначення та оператор рівності, тому оператор рівності є =. ==підтримується лише кількома останніми реалізаціями [(і є лише псевдонімом для =).

Оскільки [це не що інше, як команда, вона аналізується так само, як і будь-яка інша команда оболонкою.

Зокрема, у вашому прикладі, $aоскільки це не цитується, воно було б розділене на кілька слів за звичайними правилами розбиття слів, і кожне слово зазнало б генерації імені файлу ака-глобулінгу, що призведе до, можливо, більше слів, кожне з цих слів призведе до окремий аргумент [команди.

Так само z*було б розширено до списку імен файлів у поточному каталозі, починаючи з z.

Так, наприклад, якщо $aє b* = x, і є z1, z2, b1і b2файли в поточному каталозі, то [команда отримає 9 аргументів: [, b1, b2, =, x, ==, z1, z2і ].

[аналізує свої аргументи як умовний вираз. Ці 9 аргументів не складають дійсного умовного виразу, тому він, ймовірно, поверне помилку.

[[ ... ]]Конструкція була введена Korn оболонки , ймовірно , близько 1988 , як ksh86aв 1987 році його не було в той час як ksh88було це з самого початку.

Крім ksh (усіх реалізацій), [[...]]він також підтримується bash (починаючи з версії 2.02) та zsh, але всі три реалізації різні, і між різними версіями однієї оболонки є відмінності, хоча зміни, як правило, сумісні з зворотним ходом (помітним винятком є ​​bash's =~оператор, який, як відомо, зламав кілька сценаріїв після певної версії, коли його поведінка змінилася). [[...]]не визначено POSIX, Unix або Linux (LSB). Він кілька разів розглядався для включення, але не включався, оскільки загальна функціональність його, що підтримується основними оболонками, вже охоплена [командою та case-in-esacконструкцією.

Вся [[ ... ]]конструкція складається з команди. Тобто він має статус виходу (що є його найважливішим активом, оскільки це результат оцінювання умовного виразу), ви можете передавати його іншій команді (хоча це не буде корисно) і взагалі використовувати її де б ви не хотіли використовувати будь-яку іншу команду (лише всередині оболонки, оскільки це - оболонка), але вона не розбирається як звичайна проста команда. Те, що знаходиться всередині, розбирається оболонкою як умовний вираз, а звичайні правила розбиття слів та створення імен файлів застосовуються по-різному.

[[ ... ]]знає про це ==з самого початку і дорівнює =1 . Помилка ksh's, хоч (і викликає плутанину і багато помилок) полягає в тому, що =і ==не є оператором рівності, а оператором зіставлення шаблонів (хоча аспект відповідності може бути відключений цитуванням, але з незрозумілими правилами, що відрізняються від оболонки до оболонки).

У вашому коді вище [[ $a == z* ]], оболонка буде розбирати ці декілька лексем у правилах, подібних до звичайних, розпізнавати їх як порівняння зі зразком, трактувати z*як шаблон, який відповідає змісту aзмінної.

Взагалі, важче стріляти в ногу, [[ ... ]]ніж це за [командою. Але кілька правил, як

  • завжди цитуйте змінні
  • ніколи не використовувати -aабо -oоператор (використовувати кілька [команд і &&та || оболонки операторів)

Зробіть [надійними за допомогою оболонок POSIX.

[[...]]в різних оболонках підтримують додаткових операторів, таких як оператори -ntвідповідності повторного виклику ... але список та поведінка змінюються від оболонки до оболонки та версії до версії.

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


1 Виняток: [[...]]додано до bash у версії 2.02. До 2.03тих пір, де це було б змінено, [[ x = '?' ]]повернеться правда, тоді як [[ x == '?' ]]повернеться хибним. Тобто цитування не завадило збігу шаблонів при використанні =оператора в цих версіях, але було зроблено при використанні ==.


Чудова інформація. Чи поясніть, будь ласка, чому "ніколи не використовуйте оператора -a або -o"?
grebneke

@grebneke, спробуйте [ '!' = foo -o a = a ]в bash, наприклад.
Стефан Шазелас

0

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

[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"

[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"


Зауважте, що оболонка Bourne не є POSIX, [[...]]підтримує регулярні виразки лише в деяких версіях деяких оболонок, як і деякі версії [підтримують узгодження регулярного виразів. Для порівняння з арифметиками, в тих оболонках, які підтримують [[, ви краще напишіть(( n == 0 && y == 0))
Stéphane Chazelas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.