Наприклад, наступна команда не працює:
if [[-e xyz]]; then echo File exists;fi
ksh видає таку помилку
[[-e: command not found
Це тому, що "[[-" є неоднозначним?
Наприклад, наступна команда не працює:
if [[-e xyz]]; then echo File exists;fi
ksh видає таку помилку
[[-e: command not found
Це тому, що "[[-" є неоднозначним?
Відповіді:
Найпростіше пояснення буде, тому що в керівництві він виглядає [[ expression ]]
так , там має бути простір між [[
та expression
і закривання ]]
. Але, звичайно, ми можемо спробувати поглянути на це більш глибоко. Оболонки мають дещо складну граматику і значною мірою покладаються на поняття "розщеплення слів". Зокрема, в посібнику ksh (1) зазначено:
Оболонка починає розбирати свої дані, розбиваючи її на слова. Слова, що є послідовностями символів, розмежовуються символами пробілу без процитів (пробіл, вкладка та новий рядок) або мета-символами (<,>, |,;,, і, (і)). Крім розмежування слів, пробіли та вкладки ігноруються, а нові рядки зазвичай розмежовують команди.
Отже, як зазначено в посібнику, послідовність символів [[-e
вважається оболонковим словом. ksh
шукає таку команду у списку вбудованих та спеціальних операторів (як-от for
або while
), потім шукає зовнішню команду - і voilà - жодної не знайдено, отже, повідомлення про помилку про команду не знайдено.
У цьому випадку [[
також не є спеціальними мета-символами. Якби вони були, -e
частина в [[-e
них вважалася б оболонковим словом, а не аргументом для [[
себе. Однак [[
описується як складна команда, а в посібнику сказано наступне:
Складені команди створюються за допомогою наступних зарезервованих слів - ці слова розпізнаються лише в тому випадку, якщо вони не цитуються і якщо вони використовуються як перше слово команди (тобто, їм не може передувати призначення параметрів або перенаправлення):
Отже, [[
щоб бути визнаним складною командою, воно повинно бути першим словом команди чи списку команд, яке, згідно з попереднім визначенням слова, означає, що воно повинно бути відокремлене пробілами, вкладками чи новими рядками від інших слова / аргументи.
Ви запитали в коментарях : "Чому парсер не може зупинитися, як тільки він знайде" [["шаблон, і розглядає це як початок умовної команди?" Коротка відповідь, ймовірно, тому, що 1) вплив [
синтаксису, оскільки він був спочатку зовнішньою командою, а для відповідності POSIX стандарт існує як зовнішня команда навіть сьогодні, і 2) тому, що аналізатор оболонки побудований так. Шілл-аналізатор може розпізнати інші спеціальні символи, відмінні від простору: echo $((2+2))
і (echo foobar)
працювати чудово. Можливо, у майбутньому, коли ksh
розвиток почне відновитись або з'явиться форк або клон (як-от mksh
або pdksh
), хтось реалізує синтаксис, що не має місця [[-e
.
[[
її називають "зарезервованим словом" (див. Розділ 2.9 мови командної оболонки ). За визначенням POSIX, зарезервоване слово має бути розділене пробілами. На противагу цьому (
- оператор, а стандартні стани в розділі 2.9 "представлення включають проміжки між лексемами в тих місцях, де <blank>
s не буде необхідним (коли один з жетонів є оператором)". Дивіться пов’язану дискусію: Граматика оболонки POSIX: Чому груповій групі потрібне перше місце, але її немає?char
- це ключове слово, але ви все ще не можете писати charsomeletter = 'A';
і очікуєте, що аналізатор зупиниться після перегляду char
.
i--<=++j
, і у компілятора немає проблем з тим, що розбирати як i -- <= ++ j
.
_
). Ksh має (
як оператора , а (echo hello)
розбирає як ( echo hello )
. Це if
, {
, [[
та інші ключові слова , і ifx
, {x
і [[x
кожен один маркер - наприклад , як charsomeletter
це один C маркер. Навпаки, без котирування (x
в ksh є два лексеми - як, як i--
це два лексеми в C. Те, що це концептуально навіть означає бути оператором, відрізняється між оболонками в стилі Борна (як ksh) і C. Але Пітер А. Шнайдер зазначив: реальна лексична схожість.
Важливо зазначити, що [
це команда, а ключове слово оболонки [[
в bash та ksh засноване на [
.
[[
використовується аналогічно до [
. Іноді ви можете навіть замінити [
]
з [[
]]
без будь - яких змін в поведінці. Як [
, як і будь-яка команда, пробіл є обов'язковим між командою та її аргументами. Те саме стосується і [[
.
У нас раніше було тільки /usr/bin/[
. Зараз більшість оболонок [
вбудовані для ефективності, але синтаксис той самий. У снарядах, які надають [[
, він функціонує як більш універсальна альтернатива [
.
Ось опис для [
bash:
$ help [
[: [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
Так що [
еквівалентно test
(окрім очікування ]
аргументу в самому кінці). help test
дасть ще детальніше про це. Ви можете порівняти це help [[
.
Існує також довідкова сторінка для зовнішньої команди [
( man \[
).
У випадку
if [[-e
[
ні [[
команди немає. Повне слово [[-e
є.if [[-e
робить його тестом на справжнє / хибне. Так чи існує команда [[-e
? Це тому, що "[[-" є неоднозначним?
Так. Або ні. [[-e
це те, що це таке: нічого, що оболонка розуміє, тому передбачає, що це її власна команда. ;-)
[[-e
- це потенційно правильне (якщо дивно виглядає) ім'я команди.
Простір є роздільником та обов'язковий. Як видно з shellcheck
:
$ shellcheck gmail-browse-msgs-algorithm.sh
In gmail-browse-msgs-algorithm.sh line 847:
[[$Today != "${DaysArr[ i + DAY_DELETED_ON_NDX ]}" ]] && continue
^-- SC1035: You need a space after the [[ and before the ]].
(І ksh, і bash підтримують [[
і не працюють без місця. Shellcheck дає саме такий вихід із аналогічними скриптами ksh та bash, що містять цю помилку.)
Чому потрібні розмежувачі, пов’язані з лексемами та лексиконами .
ksh
оболонку у питанні. Bash запозичує [[
оператору ksh
і в цьому питанні їх поведінку ідентично, але я був би обережний припущень , оскільки є деякі суттєві відмінності між ksh
і bash
поведінки і внутрішніх органів . Це лише тому, що shellcheck працює на bash script, це може не обов’язково бути відповідним інструментом для ksh-скриптів. Просто щось, про що слід пам’ятати, підходячи до різних снарядів
[[
вбудовані правила. Я ні в якому разі не робив висновку, що ksh
це оболонка, яка shellcheck
могла виявити помилки. Сподіваюся, інші цінують ksh
і bash
є двома різними перекладачами. Дякую, що згадуєте про це. Також варто відзначити [[
, що баш вбудований, а [
це зовнішня команда.
[
це також вбудований в bash :) manpages.ubuntu.com/manpages/bionic/man7/bash-builtins.7.html Але ви не за горами - [
або test
потрібно, щоб бути зовнішньою командою. За часів оригінальної оболонки Борна [
насправді була зовнішньою командою, і вона існує дотепер, /usr/bin/[
оскільки POSIX вимагає, щоб вона була зовнішньою командою pubs.opengroup.org/onlinepubs/009695399/utilities/test.html В POSIX дуже небагато потрібно бути вбудованим pubs.opengroup.org/onlinepubs/009695399/idx/sbi.html Вбудований [
для ефективності
ksh
; використовувати hashbang або -s ksh
. Btw, ksh та bash [[
"вбудовані", але на відміну від ключового слова , [
це вбудована оболонка . (ksh :; whence -v [ [[
bash type [ [[
:) Вбудовані та зовнішні команди синтаксично однакові. Один із способів [[
відрізняється тим [
, що [[
пригнічує деякі розширення в своїх аргументах, які він не міг би бути вбудованим - настільки ж, як {
не міг групувати, якби це був вбудований. Це може бути тому, що {x
(або [[x
) один маркер відчуває себе дивним. Я думаю, що правильно сказати, що вбудовані та ключові слова лексично, але не синтаксично схожі. @SergiyKolodyazhnyy
[[
може бути зовнішньою командою! Тобто це може бути програма, а не якийсь синтаксис, підтримуваний безпосередньо вашою оболонкою. Підтримка синтаксису, що не містить простору, можливо, ksh
але він не працює в системах із зовнішніми, [[
тому з міркувань сумісності краще зберегти необхідний простір.
BusyBox надається [[
як зовнішня командаНаприклад, .
Оскільки [[-e
може брати участь у розширенні оболонки (її можна використовувати як
echo [[-e]*
щоб перерахувати всі файли, що починаються з літери між [
і e
включно), це було б повним безладом, якби [
і ]
були спеціальні символи, які не беруть участь у звичайному розщепленні слова, що регулюється пробілом.
[[
це ключове слово - імовірно, дерево розбору оболонки вимагає, щоб ключові слова були окреслені пробілом