Почему в bash работают вложенные кавычки в обратных кавычках?

Точнее, почему

"`command "$variable"`"

обрабатывать внешние кавычки как заключающие в себя внутренние кавычки, вместо того, чтобы расширять переменную вне каких-либо кавычек?

Точная команда, которую я использовал для проверки, похожа на пример, поднятый в другом вопросе stackoverflow о правильном методе цитирования при использовании подстановки команд:

fileName="some path with/spaces"
echo "`dirname "$fileName"`"

который правильно повторяет «какой-то путь с», вместо того, чтобы жаловаться из-за недопустимого количества аргументов.

Я прочитал справочную страницу Bash, где в главе «РАСШИРЕНИЕ» в разделе «Подстановка команд» говорится, что замена $() в новом стиле сохраняет значение любого символа между скобками, однако, что касается обратных кавычек, в нем только упоминается, что обратная косая черта работает ограниченным образом:

Когда используется форма замены обратной кавычки в старом стиле, обратная косая черта сохраняет свое буквальное значение, за исключением случаев, когда за ним следует $, ` или \. Первая обратная кавычка, которой не предшествует обратная косая черта, завершает подстановку команды.

Моя первая мысль заключалась в том, что обратные кавычки делают то же самое, за исключением упомянутого исключения, таким образом «цитируя» внутренние двойные кавычки, однако мне сказали, что это не так. Второе наблюдение, которое указало мне на это направление, заключалось в том, что

a=\$b
b=hello
echo `echo $a`

печатает "$b". Если бы обратные кавычки позволяли интерпретировать знак доллара, первая подстановка переменных должна была произойти до вызова подоболочки, при этом подоболочка расширяла строку «$b», что приводило к «привет». Согласно приведенной выше выдержке из справочной страницы, я даже могу убедиться, что знак доллара действительно заключен в кавычки, используя

echo `echo \$a`

и результаты все равно будут такими же.

Третье наблюдение вызывает у меня некоторые сомнения:

echo `echo \\a`

Результат: "\а"

echo \a

Результат: а

Здесь кажется, что обе обратные косые черты были сохранены до тех пор, пока подоболочка не вступила в игру, хотя страница руководства утверждает, что обратные косые черты в обратных кавычках не имеют своего буквального значения, когда за ними следует другая обратная косая черта. РЕДАКТИРОВАТЬ: ^ В этом отношении все работает так, как ожидалось, я, должно быть, использовал неправильную оболочку (tcsh в моем другом терминале и с другим символом, отличным от «a»).

Хотя мне не удалось узнать, что на самом деле происходит, пока я искал ответ, я наткнулся на некоторых людей, упоминающих термин «цитирование контекста» в отношении подстановки команд, но без каких-либо объяснений того, что это означает и где это описано. Я не нашел никаких реальных ссылок на «контексты цитирования» ни в ссылках Bash (gnu.org, tldp, man bash), ни через DuckDuckGo.

Вдобавок к знанию того, что происходит, я бы предпочел получить некоторую ссылку или руководство относительно того, как это поведение можно отличить от него, потому что я думаю, что, возможно, мне не удалось собрать воедино некоторые части, из которых это происходит естественным образом. Иначе я просто забуду ответ.

Тем, кто рекомендует людям использовать знак доллара в новом стиле и замену скобок: ок. Машины Unix 50-летней давности с десятками или сотнями различных проприетарных сред (нельзя выбросить оболочку для более новой), когда нужно писать сценарии, совместимые между большинством оболочек, которые кто-либо может использовать, это не вариант.

Спасибо всем, кто может мне помочь.


person Larry    schedule 13.12.2017    source источник
comment
Можете ли вы пояснить это предложение: рассматривайте внешние кавычки как заключающие в себя одинарные кавычки, а не расширяйте переменную вне каких-либо кавычек? Эта страница mywiki.wooledge.org/BashFAQ/082 может помочь понять, как ведут себя обратные кавычки. . Например, обратные косые черты обрабатываются неочевидным образом внутри обратных кавычек.   -  person calico_    schedule 14.12.2017
comment
Ваш вывод о a=\$b неверен. Интерпретация не является рекурсивной, поэтому, когда вы повторяете $a, вы возвращаете строку, которая была присвоена a, которая оказывается «$b», поэтому это было то же самое, что писать a='$b'. Вы можете использовать eval, eval echo $(echo $a)   -  person grail    schedule 14.12.2017
comment
Проще говоря, подстановка команды запускает новый контекст цитирования. Содержимое подстановки команды обрабатывается независимо от любых кавычек, в которых оно появляется.   -  person chepner    schedule 14.12.2017
comment
calico_: Спасибо, что указали на это, я по ошибке написал single вместо inner.   -  person Larry    schedule 14.12.2017
comment
chepner: не могли бы вы указать мне какую-нибудь ссылку, которая более подробно описывает контексты цитирования или это поведение? Как я уже говорил в своем посте, я уже встречал этот термин при поиске ответов, увы, без каких-либо объяснений. Было бы лучше, если бы я знал, как это вписывается во все, что описано на странице руководства Bash.   -  person Larry    schedule 14.12.2017
comment
calico_: Страница, на которую вы ссылаетесь, на самом деле не содержит ничего удивительного и ничего, что могло бы ответить на вопрос. Он также делает заявление, которое мне кажется неправильным, а именно, что вложение двойных кавычек в обратные кавычки невозможно в оболочках Korn, хотя я использую оболочку Korn, и, похоже, она работает нормально, используя пример с именем каталога. Возможно, автор имел в виду какие-то оболочки Korn, а не все. Однако в сочетании с $() он содержит дополнительное объяснение того, что такое контекст цитирования, хотя и не упоминает, что он применим и к обратным кавычкам.   -  person Larry    schedule 14.12.2017


Ответы (1)


Об этом говорится в POSIX в 2.2.3 (выделено мной ):

` (обратная цитата)

Обратная кавычка должна сохранить свое особое значение, вводя другую форму подстановки команд (см. Подстановка команд). Часть строки в кавычках от начальной обратной кавычки и символов до до следующей обратной кавычки, которой не предшествует ‹обратная косая черта›, с удаленными escape-символами, определяет ту команду, вывод которой заменяет `...` при расширении слова. Любой из следующих случаев приводит к неопределенным результатам:

  • Строка в одинарных или двойных кавычках, которая начинается, но не заканчивается в последовательности `...`

  • Последовательность `...`, которая начинается, но не заканчивается в одной и той же строке в двойных кавычках

Для меня это в значительной степени определяет то, что другие люди могли бы (неофициально?) назвать контекстом цитирования, включающим все в пределах двух последовательных обратных кавычек.

В некотором смысле, обратная кавычка является четвертой кавычкой в ​​дополнение к одинарной, двойной кавычке и обратной косой черте. Обратите внимание, что в двойных кавычках одинарные кавычки также теряют свою способность заключаться в кавычки, поэтому неудивительно, что обратные кавычки изменяют функцию двойных кавычек внутри них.

Я попробовал ваш пример с другими оболочками, такими как оболочка Almquist для FreeBSD и zsh. Как и ожидалось, они выводят some path with.

person Jens    schedule 12.07.2018