Оболонка POSIX: чи втрачає $ $ своє особливе значення, якщо він є останнім символом у слові?


17

На попелі, тире та лупі, коли я біжу

$ echo ab$

воно повертається

ab$

Це поведінка визначено POSIX або це лише звичайна умова щодо оболонок, сумісних з POSIX? Я не зміг знайти нічого на сторінці мови командної оболонки POSIX, що згадує про таку поведінку.


4
Питання краще: "Чи $ набуває особливого значення, якщо це останній символ у слові?" Не присвоєно єдиного спеціального значення $; використовується для введення декількох, але відмінних розширень, таких як розширення параметрів ${...}, підміна команд $(...)та арифметичні вирази $((...)). Деякі оболонки вводять додаткові контексти, наприклад, kshваріант підстановки команд x=${ echo foo; echo bar;}(який відрізняється від стандартного $(...)тим, що не виконує команди в підпакеті).
чепнер

@chepner Чи хотіли б ви зважитися на різницю думок між Іссаком та Майклом Гомером? Їх відповіді явно суперечать один одному
Гарольд Фішер

1
Я згоден з інтерпретацією Майкла Гомера; оболонка навіть не починає турбуватися про розширення, поки після завершення розбору не буде, тому в одному слові ab$немає жодного символу $, який був би "слідував" за нульовим символом у вихідному рядку введення чи пробілом у регістрі подобається echo ab$ foo; оригінальний пробіл без котирування був розпізнаний та відкинутий після розбору.
чепнер

Відповіді:


10

$сам по собі не має особливого значення (спробувати echo $), лише коли він поєднується з іншим символом після нього і утворює розширення, наприклад $var(або ${var}) $(util),, $((1+2)).

$Отримує свій «особливий» , що означає , як визначення розширення в стандарті POSIX в розділі Токен розпізнавання :

Якщо поточний символ є без котировки, $або `оболонка повинна ідентифікувати початок будь-яких кандидатів на розширення параметрів, підстановку команд або арифметичне розширення з їх вступних послідовностей без котирування символів: $або ${, $(або `, і $((, відповідно. Оболонка повинна прочитати достатній вхід для визначення кінця блоку, який потрібно розширити ( як пояснено у цитованих розділах). Під час обробки символів, якщо в підстановці вкладені екземпляри розширень або цитування, оболонка повинна рекурсивно обробляти їх способом, визначеним для знайденої конструкції. Символи, знайдені від початку заміни до її кінця, що дозволяють проводити будь-яку рекурсію, необхідну для розпізнавання вбудованих конструкцій, повинні бути включені незміненими в маркер результату, включаючи будь-які вбудовані або що додають оператори заміни або лапки заміщення. Маркер не повинен бути обмежений до кінця заміни.

Отже, якщо $не утворюється розширення, набувають чинності інші правила розбору:

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

Це покриває ваш ab$рядок.

У випадку з одиноким $("нове слово" було б саме $по собі):

Поточний символ використовується як початок нового слова.

Значення генерується слова містить , $який не є стандартним розширенням явно визначається як визначено з допомогою POSIX.

Також зауважте, що $це останній символ у $$, але це також буває змінною, яка містить PID поточної оболонки. В bash, !$може викликати розширення історії (останній аргумент попередньої команди). Отже, загалом, ні, $не без сенсу в кінці слова, яке не цитується, але в кінці слова воно принаймні не позначає стандартного розширення.


7

Залежно від конкретної ситуації, це явно не визначено (тому реалізація може виконуватись, як вони будуть), або вимагається, як це відбулося, як ви спостерігали. У вашому точному сценарії echo ab$, POSIX наказує висновок «аби $» , що ви спостерігали і це не визначено . Швидкий підсумок всіх різних випадків під кінець.

Є два елементи: спочатку маркірування на слова, а потім тлумачення цих слів.


Токенізація

Токенізація POSIX вимагає, щоб a, $що не є початком дійсного розширення параметра , підстановки команд або арифметичної заміни, вважати буквальною частиною побудованого WORDмаркера. Це відбувається тому, що правило 5 ("Якщо поточний символ є без котировки $або `, оболонка повинна ідентифікувати початок будь-яких кандидатів на розширення параметрів, підстановку команд або арифметичне розширення з їх вступних послідовностей без котирування символів: $або ${, $(або `, і $((відповідно" ) не застосовується, оскільки жодне з цих розширень не є життєздатним. Розширення параметра вимагає, щоб у ньому з’явилося дійсне ім’я, а порожнє ім’я недійсне.

Оскільки це правило не застосовується, ми продовжуємо дотримуватися, поки не знайдемо той, який має. Два кандидати - №8 ("Якщо попередній символ був частиною слова, до цього слова додається поточний символ.") Та №10 ("Початковий символ використовується як початок нового слова.") , які стосуються echo a$і echo $відповідно.

Існує також третій випадок форми, echo a$+bякий потрапляє через ту саму щілину, оскільки +це не назва спеціального параметра. Цей ми повернемося пізніше, оскільки він запускає різні частини правил.

Таким чином, специфікація вимагає, щоб це $було розглянуто як частину слова синтаксично, і воно може бути згодом оброблене.


Розширення слова

Після розбору введення таким чином, із $включеним у слово, розширення слів застосовуються до кожного прочитаного слова. Кожне слово обробляється індивідуально .

Вказано, що :

Якщо без котирування "$" супроводжується символом, який не є одним із наступних:

  • Числовий символ
  • Назва одного із спеціальних параметрів (див. Спеціальні параметри )
  • Дійсний перший символ імені змінної
  • A <left-curly-bracket>('{')
  • А <left-parenthesis>

результат не визначений.

"Невизначений" - це конкретний термін, що означає це

  1. Відповідна оболонка може вибрати будь-яку поведінку в цьому випадку
  2. Відповідна програма не може покладатися на якусь конкретну поведінку

У вашому прикладі echo ab$, то $ не слід будь-якого символ , так що це правило не застосовується , і невизначений результат не викликається. Просто немає розширення, наштовхуваного на $, тому він буквально присутній і роздрукований.

Там , де вона буде застосовуватися в нашому третьому випадку зверху: echo a$+b. Тут $йде далі+ , що не є число, спеціальний параметр ( @, *, #, ?, -, $, !, або 0), початок змінного імені (підкреслення або літерним від портативного набору символів ), або один з кронштейнів. У цьому випадку поведінка не визначено: відповідної оболонці дозволяється вигадувати спеціальний параметр, покликаний +розширюватись , а відповідна програма не повинна припускати, що оболонка цього не робить . Оболонка може також робити все, що їй подобається, включаючи повідомлення про помилку.

Наприклад, zsh, включаючи його в режимі POSIX, інтерпретує $+bяк "мінливий bнабір" і замінює на його місці 1 або 0. Аналогічно має розширення для ~та =. Це відповідна поведінка.

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


Підводячи підсумок

  • echo ab$: дослівний вихід, повністю вказаний
  • echo a$ b: дослівний вихід, повністю вказаний
  • echo a$ b$: дослівний вихід, повністю вказаний
  • echo a$b: розширення параметра b, повністю вказане
  • echo a$-b: розширення спеціального параметра -, повністю вказане
  • echo a$+b: невказана поведінка
  • echo "a$ b": невказана поведінка

Для слова в $кінці слова вам дозволяється покладатися на поведінку, і до неї слід ставитися буквально і передаватися echoкоманді як частина її аргументу. Це вимога відповідності оболонці.


Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
тердон

@MichaelHomer Буде echo $також буквальним і повністю вказаним?
Гарольд Фішер

@HaroldFischer Так
Майкл Гомер

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