Por que a expansão variável bash retém aspas?

12
> echo "hi"
hi
> VAR='echo "hi"'
> $VAR
"hi"

Por que a saída dos comandos acima é diferente?

O mesmo ocorre com aspas simples:

> VAR="echo 'hi'"
> $VAR
> 'hi'
Cory Klein
fonte
6
Por favor, não adquira o hábito de incorporar fragmentos de script executável em variáveis. Esta tende a ser complicado no melhor e evalé um campo minado de buracos de segurança em potencial que você deve andar com muito cuidado
jw013
@ jw013 Bom argumento e ótimos artigos. Gosto da citação "Variáveis ​​retêm dados, funções retêm código". a partir do primeiro link, mas, para meu uso, os dados fornecidos a uma função (nesse caso at) são código. Alguma dica sobre uma maneira mais segura de organizar / coletar código que será fornecido at?
Cory Klein
atrecebe a shsintaxe como entrada. Assim, gerar entrada por atmeios de gerar shsintaxe válida e adequadamente citada a partir de entrada arbitrária, o que não é trivial, portanto, tentaria evitá-la, se possível. Seria realmente útil se você desse um pouco mais de detalhes sobre o que está tentando realizar.
Jw013
Desculpe, eu não queria distrair com muitos detalhes, mas o que estou fazendo não é realmente complicado, IMO. Estou criando um script que leva um "tempo" e uma "mensagem". Em seguida, ele é executado atdurante o "tempo" especificado e diz atpara executar o comando dzen2. dzen2pega a "mensagem" de stdin e também usa outros parâmetros estáticos. A dificuldade é que eu preciso canalizar o parâmetro "message" do usuário para o dzen2comando, mas na verdade não estou me executando dzen2, estou dizendo atpara fazê-lo.
Cory Klein

Respostas:

16

O par extra de cotações seria consumido apenas por uma etapa extra de avaliação. Por exemplo, forçado por eval:

bash-4.2$ VAR='echo "hi"'

bash-4.2$ $VAR
"hi"

bash-4.2$ eval $VAR
hi

Mas geralmente é uma má idéia colocar comandos com parâmetros em uma string. Use uma matriz:

bash-4.2$ VAR=(echo "hi")

bash-4.2$ "${VAR[@]}"
hi
homem a trabalhar
fonte
1
Também é importante observar que as cotações são avaliadas de maneira diferente; aspas duplas (") permitem a avaliação da cadeia de caracteres anexada, aspas simples (') imprimem a cadeia de caracteres como um literal. Exemplo: "$(ls)"e '$(ls)'. Esta é a razão pela qual as aspas aparecem nos exemplos de perguntas originais.
Joseph Kern
Uma matriz também é uma fonte de problemas. Código pertence a funções, dados a variáveis. O exemplo que você apresenta funciona apenas porque as aspas são removidas na divisão da matriz. A printf '<%s> ' "${VAR[@]}"mostrará que as aspas já foram removidas. Se você definir o VAR VAR=(echo \"hi\")para realmente ter aspas, o mesmo problema será exibido novamente, $ ${VAR[@]}será impresso"hi"
9

A remoção de cotação ocorre apenas nas palavras de entrada originais, não no resultado de expansões. As cotações que fazem parte das variáveis ​​expandidas são intocadas.

jw013
fonte
2

Se você recuar um pouco, poderá ver por que a substituição de variáveis ​​deve reter aspas.

O objetivo das aspas em um shell Unix / Linux / BSD é manter partes de uma string juntas que, de outra forma, seriam analisadas como várias strings. Como, por padrão, um shell usa espaço em branco como separador de token, uma string com espaços (como "um dois três"), se não for citada ou escapada de alguma forma, seria analisada como três cadeias: "um", "dois" e "três".

Se um programador quiser uma string com o valor de alguma variável interpolada:

VAR=two
STRING="one $VAR three"

o shell não deve absolutamente remover as aspas: a string que contém espaços seria analisada como três strings menores.

Bruce Ediger
fonte