Що вимагає POSIX для цитованих тут документів у підстановці команд?


20

У цьому питанні хтось повідомляє про проблему, використовуючи тут документ із цитованим словом-роздільником всередині $(...)підстановки команд , де зворотний \косий рядок в кінці рядка всередині документа запускає продовження лінії приєднання нового рядка , тоді як той самий документ, що знаходиться за межами заміни команди, працює, як очікувалося .

Ось спрощений приклад документа:

cat <<'EOT'
abc ` def
ghi \
jkl
EOT

Сюди входить один зворотний відміток і один зворотний косий рядок в кінці рядка. Цитується роздільник, тому всередині тіла не відбувається розширення. У всіх подібних Bourne я можу знайти це виводить вміст дослівно. Якщо я поміщаю той самий документ всередину заміни команди, як слід:

x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"

тоді вони більше не поводяться однаково:

  • dash, ash, zsh, ksh93, BusyBox ash, mkshі SunOS 5,10 POSIX shвсе дає стенографічне зміст документа, як і раніше.
  • Bash 3.2 дає синтаксичну помилку для неперевершеного бетінгу. За допомогою збіжених задних посилань він намагається запустити вміст як команду.
  • Bash 4.3 згортає "ghi" та "jkl" на один рядок, але не має помилок. --posixОпція не впливає на це. Кусалаланда каже мені (спасибі!), Що pdkshповодиться так само .

У первісному запитанні я сказав, що це помилка в аналізаторі Баша. Є це? [Оновлення: так ] Відповідний текст з POSIX (усе з визначення мови команди командної оболонки), який я можу знайти:

  • §2.6.3 Заміна команд :

    З формою $ (команда) всі символи, що слідують за відкритими дужками до відповідних дужок, що закриваються, складають команду. Будь-який дійсний скрипт оболонки може використовуватися для команди , за винятком сценарію, що складається виключно з перенаправлень, які дають не визначені результати.

  • §2.7.4 Тут-Документ :

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

  • §.2.2.1 Характер втечі (зворотний ривок) :

    Якщо <newline> слідує за <зворотною косою>, оболонка повинна інтерпретувати це як продовження рядка. Перед розбиттям входу на лексеми повинні бути видалені <backslash> та <newline>.

  • §2.3 Розпізнавання маркера :

    Коли io_here маркер був визнаний граматикою (див Shell граматика ), один або декілька з наступних рядків відразу після наступного NEWLINE маркерів утворюють тіло одного або більше тут-документів і повинні бути розібрані в відповідно до правил тут- Документ .

    Коли вона не обробляє io_here , оболонка повинна розбити свій вхід у маркери, застосувавши перше застосоване правило нижче до наступного символу у своєму введенні. ...

    ...

    1. Якщо поточний символ є <зворотним косою>, одноцитатною або подвійною цитатою, і він не цитується, це вплине на цитування наступних символів до кінця тексту, що цитується. Правила котирування такі, як описано в цитуванні . Під час розпізнавання токенів ніякі заміни фактично не виконуються, а маркер результату повинен містити саме символи, які відображаються у вході (за винятком <newline> приєднання), немодифікованим, включаючи будь-які вбудовані або додаючі лапки або оператори підстановки, між і кінцем цитованого тексту.

Моя інтерпретація цього полягає в тому, що всі символи після закінчення $(до завершення )містять сценарій оболонки, дослівно; з'являється документ тут, тож обробка документа тут відбувається замість звичайної лексеми; у документі тут є розділений розділ, що означає, що його вміст обробляється дослівно; і персонаж втечі ніколи не впадає в нього. Я можу бачити аргумент, що цей випадок просто не вирішується, і обидва способи поведінки допустимі. Можливо, я і десь пропустив відповідний текст.


  • Чи з’ясовується ця ситуація в інших місцях?
  • На що повинен покладатися (теоретично) портативний сценарій?
  • Чи відповідає специфічна обробка будь-якої з цих оболонок (Bash 3.2 / Bash 4.3 / всі інші) стандартом? Заборонено? Дозволено?

Чи можете ви показати нам, як ви виробляєте свій результат у другому випадку?
Джулі Пелтьє

@JuliePelletier echo "$x", але будь-який спосіб перевірки змінної працює. Я відредагував цей рядок донизу.
Майкл Гомер

2
Схоже, це легко виправити. Здається, цей патч працює як мінімум: ignore_quoted_newline_in_quoted_heredoc.patch
geirha

1
Я думаю, ви правильно інтерпретуєте і imo стандарт досить зрозумілий, оскільки "оболонка повинна розширювати підстановку команд, виконуючи команду в середовищі підшару [...] і замінюючи підстановку команди [...] на стандартний вихід команда [...] " Таким чином, вона запускає команду в підклітині і замінює $(...)будь-яким тим виведенням ... Тепер, коли запускає команду у вашому прикладі в підпакеті (в bash), вона виводить очікуваний результат. Лише перетворюючи його на заміну команд, він згортає "ghi" та "jkl". Так що це помилка imo
don_crissti

2
@geirha Я повідомив про помилку Bash ; Я не збираюся турбуватися про pdksh, оскільки, здається, немає навіть тіні поточного обслуговування.
Майкл Гомер

Відповіді:


5

Про це попросили в списку розсилки Баша, і власник підтвердив, що це помилка

Вони також зазначили, що текст POSIX "не обов'язково неоднозначний, але він вимагає уважного читання", тому я попросив роз'яснити це. Їх відповідь, включаючи опис питання та тлумачення стандарту, була такою:

Заміна команди - це червона оселедець; вона актуальна лише в тому, що вона вказувала, де знаходиться помилка.

Розмежувач до цього документу цитується, тому рядки не розширюються. У цьому випадку оболонка читає рядки з вхідних даних, як ніби вони були цитовані. Якщо зворотний косий рядок з'являється в контексті, де він цитується, він не виконує функції втечі (див. Нижче), а спеціальне поводження з косою рисою нової лінії не відбувається. Насправді, якщо цитується якась частина роздільника, рядки документа тут читаються так, ніби одноцитовані.

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

Близька частина для читання - це "не розширений" текст, що передбачає єдині лапки. Стандарт в 2.2 повідомляє, що тут документи є "іншою формою цитування", але єдиною формою цитування, в якій слова зовсім не розгорнуті, є одиничні лапки. Таким чином, це форма цитування, яка приблизно подібна до одиничних цитат, але не до одиничних цитат.


@Scott (1) Я вважаю, що це відповідає на всі питання, і нічого зайвого. Мій коментар, який починається з відповіді, стосується видалення, зробленого модератором, який неправильно зрозумів ситуацію. (2) У мене недостатньо репутації. (3) Я був би вдячний за подібну поведінку тих, хто видаляє свої відповіді, але, безумовно, маю це мати на увазі в майбутньому. Дякую за думки.
Кевін

Моя думка полягала в тому, що більшість вашого першого абзацу - це розмова з Майклом Мрозеком, а не відповідь на запитання. Я розумію, що у вас недостатньо репутації, щоб коментувати будь-яку публікацію, але я вважаю, що у вас достатньо для мета та чату.
Скотт

1
@Scott Я розумію і вдячний, що ви намагаєтеся впорядкувати відповідь, але я розмістив цю саме впорядковану відповідь раніше (лише цитата та посилання на неї), і її видалив вказаний модератор (без жодної дискусії!), І я не бачити посилань у видаленій публікації, щоб спілкуватися в чаті та оскаржувати це рішення. Я сподівався, що, відповідаючи на його необґрунтовану критику, він переживе вилучення, його буде прийнято запитувачем, і тоді я зміню відповідь, щоб видалити преамбулу.
Кевін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.