вкладені подвійні лапки у високоголосний однокласник


20

StackOverflow відповідь з> 3.5K голосів показує цей один вкладиш для присвоєння DIRдиректорії поточного скрипта Баша:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Мене спантеличують вкладені подвійні лапки. Наскільки я можу сказати, такі фрагменти двічі цитуються:

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

... а все інше праворуч від =(тобто $( dirnameі )) не цитується. Іншими словами, я припускаю, що 2-й, 4-й та 6-й "символи "закривають" 1-й, 3-й та 5-й "символи відповідно.

Я розумію, чого "${BASH_SOURCE[0]}"досягають подвійні лапки , але яка мета інших двох пар подвійних лапок?

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

(Під номінальним наміром я маю на увазі: зібрати значення, повернене pwdпісля першого cd-ing, до каталогу, повернутого dirname "${BASH_SOURCE[0]}", і виконайте cd-ing у підколонці, щоб $PWDбатьківська оболонка залишалася незмінною).


1
це з - за особливості $ (...): $( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... ).
Олів'є Дулак

Я прийшов сюди через сценарій встановлення докера. Щоб знайти ім’я дистрибутива:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
Девід Тонхофер

Зауважте, що пробіли в рядку не потрібні: DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"працює також.
Девід Тонхофер

Відповіді:


12

Ваша головоломка не вірна щодо того, як bash(і оболонки взагалі) розібрали введення. В:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

По-перше, bashрозберіть праву частину завдання на одну довгу рядок, $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )оскільки подвійна цитата може з'явитися всередині подвійних лапок .

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

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Оболонка продовжує розбирати цю складову команду, розбиває її на дві частини:

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • pwd

Потім застосуйте те саме правило розбору для cd "$( dirname "${BASH_SOURCE[0]}" )", але цього разу подвійні лапки не є зайвими, але мають сенс. Вони запобігають розщепленню поля на результат $( dirname "${BASH_SOURCE[0]}" ), а також розширення ${BASH_SOURCE[0]}(На відміну від зовнішніх найбільш подвійних лапок, в РЗЗ змінної присвоєння не потрібноsplit+glob ).


Це правило стосується підстановки команд у всій оболонці POSIX . Головоломка з більш детальною інформацією ви можете прочитати в розділі Розпізнавання токенів специфікації POSIX .


21

Як тільки хтось знаходиться всередині $(...), цитування починається з нуля.

Іншими словами, "..."і $(...)можуть гніздитися всередині один одного. Процес заміщення, $(...)може містити один або більше повних рядків з подвійним цитуванням. Також рядки з подвійним цитуванням можуть містити одну або більше повних підстановок процесу. Але вони не переплітаються. Таким чином, рядок з подвійним цитуванням, який починається всередині заміни процесу, ніколи не поширюватиметься поза ним або навпаки.

Отже, врахуйте:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

Всередині $(...)знаходиться:

dirname "${BASH_SOURCE[0]}"

У наведеному вище ${BASH_SOURCE[0]}наведено подвійне цитування Будь-які котирування, подвійні або одиничні, поза межами $(...)значення не мають значення при визначенні ${BASH_SOURCE[0]}подвійних котирувань.

Зовнішній $(...)містить:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

Тут вираз $( dirname "${BASH_SOURCE[0]}" )подвійний. Те, що існують цитати поза зовнішнім $(...), не має значення при розгляді того, що знаходиться всередині нього. Те, що є внутрішні цитати $(...), також не має значення.

Ось як збігаються подвійні лапки:

введіть тут опис зображення


Що ти маєш на увазі irrelevant? За винятком зовнішньої більшості дужок, всі інші мають своє значення.
cuonglm

4
І тому не слід використовувати зворотні посилання: Правила котирування надзвичайно дивні та неінтуїтивні.
Wildcard

Речення « $(...)зв’язується міцніше, ніж "..."» не має сенсу. Вони не є операторами інфікування, і між ними немає ієрархії (якщо це було тоді, це означало б, що або лапки не можуть бути всередині дужок, або дужки не можуть бути всередині лапок, але це не так). Технічний термін - це $(…)і "…"гніздо.
Жил "ТАК - перестань бути злим"

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