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

5

Pensei em documentar isso: estou tentando algo muito simples: defina a variável env em bash e imprima:

$ bash -c "a=1; echo a$a;"
a
$ bash -c "a=1; echo a\$a;"
a1

Agora eu quero o mesmo, 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 apropriada para escape, de modo que sh -c [bash -c ...] dê o mesmo resultado que apenas bash -c ... ?

    
por sdaau 21.04.2013 / 23:57

2 respostas

2

Dentro de aspas simples, nenhum caractere tem um significado especial. Dentro de aspas duplas, "\$' tem um significado especial. Trabalhe de fora a partir de fora: primeiro descubra que cadeia é construída pela casca exterior e, em seguida, o que a casca interna fará dela.

Por exemplo, supondo que a variável a não esteja definida no shell externo, com

sh -c "bash -c \"a=1; echo a\$a;\""

o shell externo vê uma string de aspas duplas que se expande para bash -c "a=1; echo a$a;" , e é aquela 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 cadeia com aspas duplas "a=1; echo a$a;" , em que a variável a não está definida.

Se você fizer essa análise, poderá ver que uma maneira de conseguir o que deseja seria ter "a=1; echo a\$a;" nesse estágio. Para obter essa barra invertida extra, é necessário colocar duas barras invertidas no original, já que já houve um estágio de expansão do shell entre aspas duplas. Dois mais um é 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 quer expandir nada lá.

sh -c 'bash -c "a=1; echo a\$a;"'

Como você não quer expandir nada ao chamar bash de sh , 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: coloque '\'' . Formalmente, isso encerra o literal entre aspas simples, acrescenta uma aspa simples literal e inicia um novo literal com aspas simples, mas você pode pensar na sequência de quatro caracteres '\'' como sendo uma maneira de colocar uma aspa simples dentro de uma única string entre aspas.

sh -c 'bash -c '\''a=1; echo a$a;'\'''

Você pode omitir esse '' no final, é menos sistemático, mas mais fácil para os olhos.

sh -c 'bash -c '\''a=1; echo a$a;'\'

Aspas simples não são especiais entre aspas duplas, portanto, quando você escreve "bash -c 'a=1; echo a\$a;'" , você precisa da contrabarra antes do dólar para evitar a expansão de $a no shell externo.

    
por 24.04.2013 / 03:20
1

Bem, eu encontrei um casal que trabalha (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, contanto que a primeira cota única não tenha escapado, e o dólar tenha escapado - funciona, independentemente de a cota final ter escapado ou não! O que ainda me deixa um pouco confuso ...

    
por 22.04.2013 / 00:00