У цьому питанні хтось повідомляє про проблему, використовуючи тут документ із цитованим словом-роздільником всередині $(...)
підстановки команд , де зворотний \
косий рядок в кінці рядка всередині документа запускає продовження лінії приєднання нового рядка , тоді як той самий документ, що знаходиться за межами заміни команди, працює, як очікувалося .
Ось спрощений приклад документа:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Сюди входить один зворотний відміток і один зворотний косий рядок в кінці рядка. Цитується роздільник, тому всередині тіла не відбувається розширення. У всіх подібних Bourne я можу знайти це виводить вміст дослівно. Якщо я поміщаю той самий документ всередину заміни команди, як слід:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
тоді вони більше не поводяться однаково:
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
і SunOS 5,10 POSIXsh
все дає стенографічне зміст документа, як і раніше.- 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 , оболонка повинна розбити свій вхід у маркери, застосувавши перше застосоване правило нижче до наступного символу у своєму введенні. ...
...
- Якщо поточний символ є <зворотним косою>, одноцитатною або подвійною цитатою, і він не цитується, це вплине на цитування наступних символів до кінця тексту, що цитується. Правила котирування такі, як описано в цитуванні . Під час розпізнавання токенів ніякі заміни фактично не виконуються, а маркер результату повинен містити саме символи, які відображаються у вході (за винятком <newline> приєднання), немодифікованим, включаючи будь-які вбудовані або додаючі лапки або оператори підстановки, між і кінцем цитованого тексту.
Моя інтерпретація цього полягає в тому, що всі символи після закінчення $(
до завершення )
містять сценарій оболонки, дослівно; з'являється документ тут, тож обробка документа тут відбувається замість звичайної лексеми; у документі тут є розділений розділ, що означає, що його вміст обробляється дослівно; і персонаж втечі ніколи не впадає в нього. Я можу бачити аргумент, що цей випадок просто не вирішується, і обидва способи поведінки допустимі. Можливо, я і десь пропустив відповідний текст.
- Чи з’ясовується ця ситуація в інших місцях?
- На що повинен покладатися (теоретично) портативний сценарій?
- Чи відповідає специфічна обробка будь-якої з цих оболонок (Bash 3.2 / Bash 4.3 / всі інші) стандартом? Заборонено? Дозволено?
echo "$x"
, але будь-який спосіб перевірки змінної працює. Я відредагував цей рядок донизу.
$(...)
будь-яким тим виведенням ... Тепер, коли запускає команду у вашому прикладі в підпакеті (в bash
), вона виводить очікуваний результат. Лише перетворюючи його на заміну команд, він згортає "ghi" та "jkl". Так що це помилка imo