%20con%20comandos%20le%C3%ADdos%20de%20args%20y%20%22cadena%20entre%20comillas%20no%20terminada%22%2F%22EOF%20inesperado%22.png)
Solo pensé en documentar esto: estoy intentando algo muy simple: configurar la variable env bash
e imprimirla:
$ bash -c "a=1; echo a$a;"
a
$ bash -c "a=1; echo a\$a;"
a1
Ahora me gustaría lo mismo, pero llamado como argumento de sh
(en mi sistema, ls -la $(which sh)
da /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
Entonces, mi pregunta sería: ¿cuál es la sintaxis adecuada para escapar, de modo que sh -c [bash -c ...]
dé el mismo resultado que just bash -c ...
?
Respuesta1
Entre comillas simples, ningún carácter tiene un significado especial. Entre comillas dobles, "\$`
tienen un significado especial. Trabaje desde afuera hacia adentro: primero averigüe qué cuerda está construida por la capa exterior, luego qué hará la capa interior con ella.
Por ejemplo, suponiendo que la variable a
no está definida en el caparazón exterior, con
sh -c "bash -c \"a=1; echo a\$a;\""
el caparazón exterior ve una cadena entre comillas dobles que se expande hasta bash -c "a=1; echo a$a;"
, y es esa cadena la que se pasa al intermedio sh
. sh
analiza esto como una llamada a bash
con los dos argumentos -c
y a=1; echo a;
, este último resultante de expandir la cadena entre comillas dobles "a=1; echo a$a;"
donde la variable a
no está definida.
Si haces este análisis podrás ver que una forma de conseguir lo que quieres sería tenerlo "a=1; echo a\$a;"
en esta etapa. Para obtener esta barra invertida adicional, debe colocar dos barras invertidas en el original, ya que ya ha habido una etapa de expansión del shell entre comillas dobles. Dos más uno son tres.
sh -c "bash -c \"a=1; echo a\\\$a;\""
Sería más sencillo usar comillas simples para la cadena exterior, ya que no desea expandir nada allí.
sh -c 'bash -c "a=1; echo a\$a;"'
Como no desea expandir nada cuando llama bash
desde sh
ninguno de los dos, también puede usar comillas simples allí. No puedes poner comillas simples dentro de una cadena entre comillas simples, pero hay una manera de simular esto: put '\''
. Formalmente, esto termina el literal entre comillas simples, agrega una comilla simple literal e inicia un nuevo literal entre comillas simples, pero puede pensar en la secuencia de cuatro caracteres '\''
como una forma de poner una comilla simple dentro de una cadena entre comillas simples.
sh -c 'bash -c '\''a=1; echo a$a;'\'''
Puedes omitir eso ''
al final, es menos sistemático pero más agradable a la vista.
sh -c 'bash -c '\''a=1; echo a$a;'\'
Las comillas simples no son especiales dentro de las comillas dobles, por lo que cuando escribes "bash -c 'a=1; echo a\$a;'"
necesitas la barra invertida antes del dólar para evitar la expansión de $a
en la capa exterior.
Respuesta2
Bueno, encontré un par que funcionan (NB, este es Ubuntu 11.04):
$ sh -c "bash -c 'a=1; echo a\$a \'"
a1
$ sh -c "bash -c 'a=1; echo a\$a;'"
a1
... y parece que, siempre que no se escape la primera comilla simple y se escape el dólar, ¡funciona, independientemente de si se escapa la comilla simple final o no! Lo cual todavía me desconcierta bastante...