Відповіді:
Різниця між [[ … ]]
і [ … ]
в основному покривається у використанні одинарного або подвійного дужок - bash . Принципово важливим [[ … ]]
є спеціальний синтаксис, тоді як [
команда - смішна на вигляд назва. [[ … ]]
має спеціальні правила синтаксису для того, що знаходиться всередині, [ … ]
не має.
З доданою зморшкою підстановки, ось як [[ $a == z* ]]
оцінюється:
[[ … ]]
умовна конструкція навколо умовного виразу $a == z*
.==
двійковий оператор, з операндами $a
та z*
.a
.==
оператора: перевірити, чи відповідає значення змінної a
шаблону z*
.Ось як [ $a == z* ]
оцінюється:
[
команда з аргументами , утворених оцінки слова $a
, ==
, z*
, ]
.$a
на значення змінної a
.a
є рядок 6 символів foo b*
(отримана , наприклад a='foo b*'
) , і список файлів в поточному каталозі ( bar
, baz
, qux
, zim
, zum
), то результат розкладання є наступним списком слів: [
, foo
, bar
, baz
, ==
, zim
, zum
, ]
.[
з параметрами, отриманими на попередньому кроці.
[
команда скаржиться на синтаксичну помилку і повертає статус 2.Примітка. На [[ $a == z* ]]
етапі 3 значення a
не зазнає розщеплення слів та створення імені файлів, оскільки воно знаходиться в контексті, коли очікується одне слово (лівий аргумент умовного оператора ==
). У більшості випадків, якщо одне слово має сенс на цій позиції, то змінне розширення веде себе так, як це відбувається у подвійних лапках. Однак є виняток із цього правила: у [[ abc == $a ]]
випадку, якщо значення a
містить символи підстановки, a
воно співпадає з шаблоном підстановки. Наприклад, якщо значення a
є a*
те [[ abc == $a ]]
істинно (бо підстановлювальний *
виходячи з котирувального розширення $a
матчів *
) , тоді як [[ abc == "$a" ]]
помилково (так як звичайний символ*
що походить від цитованого розширення $a
не відповідає bc
). Всередині [[ … ]]
, подвійні лапки не роблять різниці, крім як на правій стороні операторів рядки відповідності ( =
, ==
, !=
і =~
).
[
- псевдонім для 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 == '?' ]]
повернеться хибним. Тобто цитування не завадило збігу шаблонів при використанні =
оператора в цих версіях, але було зроблено при використанні ==
.
[ '!' = foo -o a = a ]
в bash
, наприклад.
обидва використовуються для оцінки виразів, і [[не працюватиме з POSIX-старшою оболонкою, і [[також підтримує узгодження шаблонів і регулярний вираз. Пример спробуйте
[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"
[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"
[[...]]
підтримує регулярні виразки лише в деяких версіях деяких оболонок, як і деякі версії [
підтримують узгодження регулярного виразів. Для порівняння з арифметиками, в тих оболонках, які підтримують [[
, ви краще напишіть(( n == 0 && y == 0))