Primeiro, xargs
não pode funcionar aqui porque as substituições seriam executadas em um subprocesso (o bash
processa esse xargs
lança). Mas apenas variáveis de ambiente são passadas para subprocessos, não para variáveis de shell. Evidentemente, HOSTNAME
já estava no ambiente do seu script quando começou, mas HOSTADDRESS
não está. Neste ponto, você pode ser tentado a exportar todas as variáveis, mas mesmo assim xargs
não é uma boa solução porque sofre de numerosos problemas de cotação - se o seu modelo contém \"'
ou se você deseja manter o espaço em branco, torrada.
Agora, olhando para o seu código atual: MESSAGE='eval echo $TEMPLATE'
é uma maneira complexa de escrever eval MESSAGE=$TEMPLATE
, exceto para problemas de cotação. E você tem citando problemas; por exemplo, você notará que todo o seu espaço em branco foi recolhido. Você já ouviu falar de Bobby Tables , não é? As regras de expansão do shell são bastante complexas, mas há algumas regras que manterão você sensato:
- Sempre aspas duplas em torno de substituições de variáveis
"$foo"
e substituições de comandos"$(bar)"
. Você pode violar esta regra se entender por que precisa omitir as aspas. - Use
$(…)
em vez de'…'
para substituições de comandos. As citações dentro do formulário backquote são arcanas e não portáveis, enquanto que a cotação dentro de$(…)
funciona normalmente. - Use
eval
somente se pressionado na mira da arma. Se fizer isso, tenha muito cuidado e torne-o o mais simples possível.
Então, o que pode dar errado com eval MESSAGE="$TEMPLATE"
? Faz o shell avaliar
MESSAGE=Hostname : $HOSTNAME
Host Address : $HOSTADDRESS
Opa, precisamos de cotações em torno da peça que deve ser o valor de MESSAGE
. As citações precisam passar para eval
, então elas precisam passar literalmente pelo primeiro estágio da expansão do shell: eval MESSAGE="\"$TEMPLATE\""
.
MESSAGE="Hostname : $HOSTNAME
Host Address : $HOSTADDRESS"
Melhor, mas agora você tem exatamente o padrão de injeção do Bobby Tables - e se o modelo contiver uma cotação? Então você precisa escapar das cotações. Os quatro caracteres que têm um significado especial entre aspas duplas são \"$'
e você deseja que $
retenha seu significado, portanto, adicione uma barra invertida antes dos outros três.
TEMPLATE=$(sed -e 's/[\"']/\&/g' <template.txt)
eval MESSAGE="\"$TEMPLATE\""
Agora o shell avaliará
MESSAGE="Hostname : $HOSTNAME
Host Address : $HOSTADDRESS
Name : Bobby \"drop\" O'Tables"
e tudo está bem.
Observe que a citação correta aqui é para proteger contra problemas de análise acidental; quem controla o modelo ainda tem acesso ao shell (com $(hello)
).
Se você quisesse o modelo incluído no seu script de shell, isso seria feito naturalmente com um heredoc .
MESSAGE=$(cat <<EOF)
Hostname : $HOSTNAME
Host Address : $HOSTADDRESS
EOF
Mas com um template externo você precisaria fazer duas etapas de avaliação, portanto use eval
, e a análise de bash é bastante bugs quando se trata de coisas funky como heredocs dentro de eval
. Há certamente uma maneira que funciona, pelo menos com o bash 4, mas eu não recomendo arriscar.