Чому потрібно вказати пробіл між "[[" та "-e xxx" в ksh?


9

Наприклад, наступна команда не працює:

if [[-e xyz]]; then echo File exists;fi

ksh видає таку помилку

[[-e: command not found

Це тому, що "[[-" є неоднозначним?


2
[[це ключове слово - імовірно, дерево розбору оболонки вимагає, щоб ключові слова були окреслені пробілом
steeldriver

Інший спосіб поглянути на це, ймовірно, ви могли б написати функцію [[-, як би оболонка знала розбирати "робити прапор е на [[" замість "виконувати функцію [[- на е".
pbhj

Відповіді:


15

Найпростіше пояснення буде, тому що в керівництві він виглядає [[ expression ]]так , там має бути простір між [[та expressionі закривання ]]. Але, звичайно, ми можемо спробувати поглянути на це більш глибоко. Оболонки мають дещо складну граматику і значною мірою покладаються на поняття "розщеплення слів". Зокрема, в посібнику ksh (1) зазначено:

Оболонка починає розбирати свої дані, розбиваючи її на слова. Слова, що є послідовностями символів, розмежовуються символами пробілу без процитів (пробіл, вкладка та новий рядок) або мета-символами (<,>, |,;,, і, (і)). Крім розмежування слів, пробіли та вкладки ігноруються, а нові рядки зазвичай розмежовують команди.

Отже, як зазначено в посібнику, послідовність символів [[-eвважається оболонковим словом. kshшукає таку команду у списку вбудованих та спеціальних операторів (як-от forабо while), потім шукає зовнішню команду - і voilà - жодної не знайдено, отже, повідомлення про помилку про команду не знайдено.

У цьому випадку [[також не є спеціальними мета-символами. Якби вони були, -eчастина в [[-eних вважалася б оболонковим словом, а не аргументом для [[себе. Однак [[описується як складна команда, а в посібнику сказано наступне:

Складені команди створюються за допомогою наступних зарезервованих слів - ці слова розпізнаються лише в тому випадку, якщо вони не цитуються і якщо вони використовуються як перше слово команди (тобто, їм не може передувати призначення параметрів або перенаправлення):

Отже, [[щоб бути визнаним складною командою, воно повинно бути першим словом команди чи списку команд, яке, згідно з попереднім визначенням слова, означає, що воно повинно бути відокремлене пробілами, вкладками чи новими рядками від інших слова / аргументи.


Ви запитали в коментарях : "Чому парсер не може зупинитися, як тільки він знайде" [["шаблон, і розглядає це як початок умовної команди?" Коротка відповідь, ймовірно, тому, що 1) вплив [синтаксису, оскільки він був спочатку зовнішньою командою, а для відповідності POSIX стандарт існує як зовнішня команда навіть сьогодні, і 2) тому, що аналізатор оболонки побудований так. Шілл-аналізатор може розпізнати інші спеціальні символи, відмінні від простору: echo $((2+2))і (echo foobar)працювати чудово. Можливо, у майбутньому, коли kshрозвиток почне відновитись або з'явиться форк або клон (як-от mkshабо pdksh), хтось реалізує синтаксис, що не має місця [[-e.

Дивись також:


3
Я думаю, що цитатна інструкція ksh дійсно знаходиться на місці. Він схожий з будь-якою іншою мовою програмування: У C char- це ключове слово, але ви все ще не можете писати charsomeletter = 'A';і очікуєте, що аналізатор зупиниться після перегляду char.
Пітер -

Я думаю, що головна відмінність вашого прикладу "char" та символу "[[" у питанні полягає в тому, що алфавітно-цифровий ідентифікатор, як правило, потребує роздільника простору для відокремлення від інших; спеціальні символи як жетони, з іншого боку, не потребують розмежувачів місця.
AcBap

Саме так. Я не впевнений, що порівняння з C корисне. У C можна сказати i--<=++j, і у компілятора немає проблем з тим, що розбирати як i -- <= ++ j.
Скотт

@Scott Я думаю, що порівняння C є корисним (і що це свого роду вторинне, що ідентифікатори C дозволяють лише буквено-цифрові та _). Ksh має (як оператора , а (echo hello)розбирає як ( echo hello ). Це if, {, [[та інші ключові слова , і ifx, {xі [[xкожен один маркер - наприклад , як charsomeletterце один C маркер. Навпаки, без котирування (xв ksh є два лексеми - як, як i--це два лексеми в C. Те, що це концептуально навіть означає бути оператором, відрізняється між оболонками в стилі Борна (як ksh) і C. Але Пітер А. Шнайдер зазначив: реальна лексична схожість.
Елія Каган

2

Важливо зазначити, що [це команда, а ключове слово оболонки [[в 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це те, що це таке: нічого, що оболонка розуміє, тому передбачає, що це її власна команда. ;-)


"% help [[" говорить, що "[[" - умовна команда. Чому аналізатор не може зупинитися, як тільки він знайде шаблон "[[", і трактує це як початок умовної команди?
AcBap

@Myloti [[-e- це потенційно правильне (якщо дивно виглядає) ім'я команди.
Гордон Девіссон

2

Простір є роздільником та обов'язковий. Як видно з 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-скриптів. Просто щось, про що слід пам’ятати, підходячи до різних снарядів
Сергій Колодяжний,

@SergiyKolodyazhnyy Мені приємно застосовувати шелчек, щоб виділити [[вбудовані правила. Я ні в якому разі не робив висновку, що kshце оболонка, яка shellcheckмогла виявити помилки. Сподіваюся, інші цінують kshі bashє двома різними перекладачами. Дякую, що згадуєте про це. Також варто відзначити [[, що баш вбудований, а [це зовнішня команда.
WinEunuuchs2Unix

Насправді [це також вбудований в 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 Вбудований [для ефективності
Сергій Колодяжний

2
Шелчек знає ksh; використовувати hashbang або -s ksh. Btw, ksh та bash [["вбудовані", але на відміну від ключового слова , [це вбудована оболонка . (ksh :; whence -v [ [[bash type [ [[:) Вбудовані та зовнішні команди синтаксично однакові. Один із способів [[відрізняється тим [, що [[пригнічує деякі розширення в своїх аргументах, які він не міг би бути вбудованим - настільки ж, як {не міг групувати, якби це був вбудований. Це може бути тому, що {x(або [[x) один маркер відчуває себе дивним. Я думаю, що правильно сказати, що вбудовані та ключові слова лексично, але не синтаксично схожі. @SergiyKolodyazhnyy
Елія Каган

1
@EliahKagan Насправді я розмістив запитання на U&L, щоб отримати точну відповідь про те, що POSIX думає про цю ситуацію unix.stackexchange.com/questions/526574/… Мова оболонки досить складна, тому, сподіваємось, хтось може пояснити це у більш формальних термінах
Сергій Колодяжний

1

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

BusyBox надається [[як зовнішня командаНаприклад, .


0

Оскільки [[-eможе брати участь у розширенні оболонки (її можна використовувати як

echo [[-e]*

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

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