Як збігаються подвійні лапки (bash)?


15

Я використовую GNU bash 4.3.48. Розглянемо наступні дві команди, які відрізняються лише знаком одного долара.

Команда 1:

echo "(echo " * ")"

Команда 2:

echo "$(echo " * ")"

Вихід з них відповідно

(echo  test.txt ppcg.sh )

і

 * 

Тож очевидно, що в першому випадку *глобус є глобусом, що означає, що перший лапки йде з другим, щоб утворювати пару, а третій і четвертий утворюють іншу пару.

У другому випадку *a не є глобусом, і у виході є рівно два зайвих пробіли, один перед зірочкою та один після, тобто, другий лапки йде з третім, а перший йде з четвертим.

Чи є інші випадки, крім $()конструкції, що лапки не відповідають наступному, а замість них вкладені? Чи добре це зафіксовано таку поведінку і якщо так, то де я можу знайти відповідний документ?



Знову ж таки, підсвітка синтаксису в UL SE є неправильною та оманливою, хоча винний саме JS.
Вейджун Чжоу

Відповіді:


14

Будь-яка з вкладених конструкцій, яка може бути інтерпольована всередині рядків, може мати додаткові рядки всередині них: вони розбираються як новий сценарій, аж до маркера закриття, і навіть можуть бути вкладені кілька рівнів глибоко. Весь рядок із них починається з значка "a" $. Усі вони задокументовані у поєднанні посібника Bash та специфікації мови командної оболонки POSIX.

Є кілька випадків цих конструкцій:

  • Заміна команд на$( ... ) , як ви знайшли. POSIX визначає таку поведінку :

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

    Котирування є частиною дійсних скриптів оболонки, тому їм дозволено їх нормальне значення.

  • Підстановка команд також використовується `.
  • Елемент "word" розширених екземплярів заміни параметрів, таких як${parameter:-word} . Визначення «слова» є :

    Послідовність символів, оброблених оболонкою як одиниця

    - який включає цитований текст і навіть змішані цитати a"b"c'd'e- хоча реальна поведінка розширень трохи ліберальніша, ніж це, наприклад, також ${x:-hello world}працює.

  • Арифметичне розширення за допомогою $(( ... )), хоча там значною мірою марно (але ви також можете вкладати підстановку команд або змінні розширення, а потім мати цитати з користю всередині них). POSIX стверджує, що :

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

    тому така поведінка прямо вимагається. Це означає echo "abc $((4 "*" 5))"арифметику, а не глобус.

    Зауважте, що $[ ... ]арифметичне розширення старого стилю не трактується однаково: цитати будуть помилками, якщо вони з’являються, незалежно від того, розширюється котирування чи ні. Ця форма більше не задокументована і не призначена для використання в будь-якому випадку.

  • Специфічний для локального перекладу текст$"..." , який фактично використовує "як основний елемент. $"трактується як єдине ціле.

Є ще один випадок гніздування, якого, можливо, ви не очікуєте, не залучаючи цитати, що з розширенням дужок : {a,b{c,d},e}розширюється до "a bc bd e". ${x:-a{b,c}d}робить НЕ гніздо, однак; це трактується як заміна параметра, що дає " a{b,c", а потім " d}". Це також документально підтверджено :

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


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

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

Ви можете вкласти цитати так глибоко, як вам подобається, через ці конструкції, і це буде працювати, як очікувалося. Ніде не заплутаєтесь, побачивши цитату посередині; натомість це стане початком нової цитованої рядки в інтер'єрному контексті.


Спасибі. У "blah/blah\n$(cat "${tmpdir}/${filename}.jpdf")"чому, чому друга подвійна цитата не є кінцем першої подвійної цитати (як показано підсвічуванням синтаксису у вашій відповіді), а початком рядка всередині $(...)? Це тому, що аналізатор bash знаходиться зверху вниз, а не знизу вгору?
Тім

2
Існує багато відмінностей в обробці "${var-"foo"}"( echo "${-+"*"}"таке ж , як echo *в Bourne або Korn оболонки, наприклад) , і поведінка буде чітко визначено в наступній версії стандарту . Дивіться також обговорення на mail-archive.com/austin-group-l@opengroup.org/msg00167.html
Stéphane Chazelas

3

Можливо, перегляд двох прикладів із printf(замість echo) допоможе:

$ printf '<%s> ' "(echo " * ")"; echo
<(echo > <test.txt> <ppcg.sh> <file1> <file2> <file3> <)>

Він друкує (echo (перше слово, включаючи пробіл), деякі файли та завершальне слово ).
Дужки є лише частиною цитованого рядка (echo .
Зірочка (зараз без котирування, оскільки дві подвійні лапки є парними) розширюється як глобус до списку відповідних файлів.
А потім, дужки, що закриваються.

Однак ваша друга команда працює наступним чином:

$ printf '<%s> ' "$(echo " * ")" ; echo
< * >

$Починає заміну команди. Це починає нове цитування.
Зірочка цитується, " * "і саме це echoвидає команда (тут це команда, а не цитується рядок) . Нарешті, printfпереформатуйте *і надрукуйте його як < * >.

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