只是想记录下来:我正在尝试一些非常简单的事情 - 设置环境变量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;"
在这个阶段获得。为了获得这个额外的反斜杠,您需要在原始文件中添加两个反斜杠,因为双引号内已经有一个 shell 扩展阶段。二加一等于三。
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
...看起来,只要第一个单引号没有转义,并且美元也被转义 - 它就有效,无论最后的单引号是否被转义!这仍然让我很困惑......