%20com%20comandos%20lidos%20de%20args%20e%20%22String%20entre%20aspas%20n%C3%A3o%20terminada%22%2F%22EOF%20inesperado%22.png)
Apenas pensei em documentar isso: estou tentando algo muito simples - definir a variável env bash
e imprimi-la:
$ bash -c "a=1; echo a$a;"
a
$ bash -c "a=1; echo a\$a;"
a1
Agora eu gostaria da mesma coisa, mas chamado como argumento de sh
(no meu sistema, ls -la $(which sh)
dá /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
Então, minha pergunta seria: qual é a sintaxe adequada para escapar, de modo que sh -c [bash -c ...]
dê o mesmo resultado que just bash -c ...
?
Responder1
Dentro das aspas simples, nenhum caractere tem um significado especial. Dentro das aspas duplas, "\$`
têm um significado especial. Trabalhe de fora para dentro: primeiro descubra qual corda é construída pela casca externa e depois o que a casca interna fará com ela.
Por exemplo, supondo que a variável a
não esteja definida na camada externa, com
sh -c "bash -c \"a=1; echo a\$a;\""
o shell externo vê uma string entre aspas duplas que se expande para bash -c "a=1; echo a$a;"
, e é essa string que é passada para o intermediário sh
. sh
analisa isso como uma chamada para bash
com os dois argumentos -c
e a=1; echo a;
, o último resultante da expansão da string entre aspas duplas "a=1; echo a$a;"
onde a variável a
não está definida.
Se você fizer essa análise poderá perceber que uma forma de conseguir o que deseja seria ter "a=1; echo a\$a;"
nesta fase. Para obter essa barra invertida extra, você precisa colocar duas barras invertidas no original, pois já houve um estágio de expansão do shell entre aspas duplas. Dois mais um são três.
sh -c "bash -c \"a=1; echo a\\\$a;\""
Seria mais simples usar aspas simples para a string externa, já que você não deseja expandir nada ali.
sh -c 'bash -c "a=1; echo a\$a;"'
Como você não deseja expandir nada ao ligar bash
, sh
você também pode usar aspas simples. Você não pode colocar aspas simples dentro de uma string entre aspas simples, mas há uma maneira de simular isso: put '\''
. Formalmente, isso termina o literal entre aspas simples, acrescenta uma aspa simples literal e inicia um novo literal entre aspas simples, mas você pode pensar na sequência de quatro caracteres '\''
como uma maneira de colocar uma aspa simples dentro de uma string entre aspas simples.
sh -c 'bash -c '\''a=1; echo a$a;'\'''
Você pode omitir isso ''
no final, é menos sistemático, mas mais agradável aos olhos.
sh -c 'bash -c '\''a=1; echo a$a;'\'
As aspas simples não são especiais dentro das aspas duplas; portanto, ao escrever, "bash -c 'a=1; echo a\$a;'"
você precisa da barra invertida antes do dólar para evitar a expansão $a
na camada externa.
Responder2
Bem, encontrei alguns que funcionam (NB, este é o Ubuntu 11.04):
$ sh -c "bash -c 'a=1; echo a\$a \'"
a1
$ sh -c "bash -c 'a=1; echo a\$a;'"
a1
... e parece que, desde que a primeira cotação simples não tenha escape e o dólar escape - funciona, independentemente de a cotação única final ter escapado ou não! O que ainda me intriga um pouco...