вложенные двойные кавычки в однолинейных с высоким рейтингом

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родительская оболочка осталась неизменной).

KJo
источник
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]}(в отличие от самых внешних двойных кавычек, в RHS при назначении переменных нет необходимости предотвращатьsplit+glob ).


Это правило применяется к подстановке команд во всех оболочках POSIX . Более подробную информацию вы можете прочитать в разделе «Распознавание токенов» спецификации POSIX .

cuonglm
источник
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]}" )в двойных кавычках. Факт, что есть кавычки вне внешнего, не $(...)имеет значения, рассматривая то, что находится внутри этого. Тот факт, что внутри есть кавычки, $(...)также не имеет значения.

Вот как совпадают двойные кавычки:

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

John1024
источник
Что ты имеешь ввиду irrelevant? За исключением самых внешних скобок, все остальные имеют свое собственное значение.
cuonglm
4
И вот почему вы не должны использовать обратные пометки: правила цитирования чрезвычайно странные и не интуитивно понятные.
Подстановочный
Предложение « $(...)крепче, чем "..."» не имеет смысла. Они не являются инфиксными операторами, и между ними нет иерархии (если бы существовала тогда, это означало бы, что либо кавычки не могут быть внутри скобок, либо скобки не могут быть внутри кавычек, но это не так). Технический термин таков $(…)и "…"гнездится.
Жиль "ТАК - перестань быть злым"
@ Жиль Очень хорошо. Я просто переформулировал это в надежде лучше понять концепцию.
John1024