Chamando bash de sh (traço) com comandos lidos de args e "String entre aspas não terminada"/"EOF inesperado"

Chamando bash de sh (traço) com comandos lidos de args e "String entre aspas não terminada"/"EOF inesperado"

Apenas pensei em documentar isso: estou tentando algo muito simples - definir a variável env bashe 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)/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 anã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. shanalisa isso como uma chamada para bashcom os dois argumentos -ce a=1; echo a;, o último resultante da expansão da string entre aspas duplas "a=1; echo a$a;"onde a variável anã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, shvocê 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 $ana 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...

informação relacionada