%20%D1%81%20%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0%D0%BC%D0%B8%2C%20%D1%81%D1%87%D0%B8%D1%82%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC%D0%B8%20%D0%B8%D0%B7%20%D0%B0%D1%80%D0%B3%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2%2C%20%D0%B8%20%C2%AB%D0%9D%D0%B5%D0%B7%D0%B0%D0%B2%D0%B5%D1%80%D1%88%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F%20%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B0%20%D0%B2%20%D0%BA%D0%B0%D0%B2%D1%8B%D1%87%D0%BA%D0%B0%D1%85%C2%BB%2F%C2%AB%D0%BD%D0%B5%D0%BE%D0%B6%D0%B8%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9%20EOF%C2%BB.png)
Просто подумал, что стоит это задокументировать: я пробую что-то очень простое — устанавливаю переменную env в bash
, и вывожу ее на печать:
$ bash -c "a=1; echo a$a;"
a
$ bash -c "a=1; echo a\$a;"
a1
Теперь я хотел бы сделать то же самое, но вызвать его как аргумент sh
(в моей системе ls -la $(which sh)
это дает /bin/sh -> dash
):
$ sh -c "bash -c "a=1; echo a\$a;""
a$a
# obviously I have to escape inner quotes:
$ sh -c "bash -c \"a=1; echo a\$a;\""
a
# escape the dollar once more?
$ sh -c "bash -c \"a=1; echo a\\$a\" "
sh: Syntax error: Unterminated quoted string
# nope... inner single quotes, then?
$ sh -c "bash -c 'a=1; echo a$a;'"
a
# nope... escape the single quotes?
$ sh -c "bash -c \'a=1; echo a$a;\'"
bash: -c: line 0: unexpected EOF while looking for matching `''
bash: -c: line 1: syntax error: unexpected end of file
a
sh: ': not found
# nope... escape the dollar too?
$ sh -c "bash -c \'a=1; echo a\$a;\'"
bash: -c: line 0: unexpected EOF while looking for matching `''
bash: -c: line 1: syntax error: unexpected end of file
a
sh: ': not found
Итак, мой вопрос - каков правильный синтаксис для экранирования, чтобы он sh -c [bash -c ...]
давал тот же результат, что и просто bash -c ...
?
решение1
Внутри одинарных кавычек нет символов, имеющих особое значение. Внутри двойных кавычек "\$`
есть особое значение. Разберитесь снаружи внутрь: сначала выясните, какая строка создана внешней оболочкой, а затем что сделает из нее внутренняя оболочка.
Например, предположим, что переменная a
не определена во внешней оболочке, с
sh -c "bash -c \"a=1; echo a\$a;\""
внешняя оболочка видит строку в двойных кавычках, которая расширяется до bash -c "a=1; echo a$a;"
, и именно эта строка передается промежуточной оболочке sh
. sh
анализирует это как вызов bash
с двумя аргументами -c
и a=1; echo a;
, причем последний получается в результате расширения строки в двойных кавычках, "a=1; echo a$a;"
где переменная a
не определена.
Если вы проведете этот анализ, то увидите, что один из способов получить то, что вам нужно, — это иметь "a=1; echo a\$a;"
на этом этапе. Чтобы получить этот дополнительный обратный слеш, вам нужно поставить два обратных слеша в оригинале, поскольку уже был один этап расширения оболочки внутри двойных кавычек. Два плюс один равно трем.
sh -c "bash -c \"a=1; echo a\\\$a;\""
Было бы проще использовать одинарные кавычки для внешней строки, поскольку вы не хотите ничего там расширять.
sh -c 'bash -c "a=1; echo a\$a;"'
Поскольку вы не хотите ничего расширять при вызове bash
из sh
любого из них, вы можете использовать одинарные кавычки и там. Вы не можете поместить одинарные кавычки внутрь строки в одинарных кавычках, но есть способ имитировать это: put '\''
. Формально это завершает литерал в одинарных кавычках, добавляет литерал одинарной кавычки и начинает новый литерал в одинарных кавычках, но вы можете думать о последовательности из четырех символов '\''
как о способе поместить одинарную кавычку внутрь строки в одинарных кавычках.
sh -c 'bash -c '\''a=1; echo a$a;'\'''
Вы можете опустить это ''
в конце, это менее систематично, но приятнее для глаз.
sh -c 'bash -c '\''a=1; echo a$a;'\'
Одинарные кавычки не являются специальными внутри двойных кавычек, поэтому при написании "bash -c 'a=1; echo a\$a;'"
вам необходимо ставить обратную косую черту перед знаком доллара, чтобы предотвратить расширение $a
во внешней оболочке.
решение2
Ну, я нашел пару работающих (обратите внимание, это Ubuntu 11.04):
$ sh -c "bash -c 'a=1; echo a\$a \'"
a1
$ sh -c "bash -c 'a=1; echo a\$a;'"
a1
... и похоже, пока первая одинарная кавычка не экранирована, а доллар экранирован - это работает, независимо от того, экранирована последняя одинарная кавычка или нет! Что меня до сих пор немного озадачивает...