Pesadelo de citações aninhadas: enviando um e-mail de um host remoto

2

Eu preciso enviar (do meu terminal) um email com anexos do meu host remoto que eu acesse pelo ssh. Eu já sei que para fazer algo remotamente, eu uso

ssh -p myport [email protected] "doSomething"

Eu também sei que para enviar um e-mail com anexos, eu faço

echo "Mail content" | mailx -s "Mail title" -a attachment.txt -S from="myname@gmail" destname@gmail

Assim, a combinação ingênua dos dois seria simplesmente substituir doSomething na primeira linha com toda a segunda linha. Isso não funciona, é claro, por causa das terríveis citações duplas aninhadas. Como fazer isso funcionar (e de forma limpa, se possível)? Qualquer ajuda apreciada.

    
por Ewan Delanoy 28.09.2017 / 16:30

1 resposta

6

Para casos simples, você pode usar aspas simples para proteger seu comando do shell local ou escapar das aspas duplas como \" .

echo "Mail content" | ssh -p myport [email protected] 'mailx -s "Mail title" -a attachment.txt -S from="myname@gmail" destname@gmail'
# or
echo "Mail content" | ssh -p myport [email protected] "mailx -s \"Mail title\" -a attachment.txt -S from=\"myname@gmail\" destname@gmail"

Para coisas mais complicadas, o mais fácil pode ser usar um heredoc para definir uma variável:

read -r -d '' mailcmd <<'CMD'
echo "quotin'" 'this would be a "nightmare" indeed.' | mailx -s "Anthony's Email" -a attachment.txt -S from="myname@gmail" destname@gmail
CMD
ssh -p myport [email protected] "$mailcmd"

Pelo menos no bash, você pode pedir ao shell para citar uma variável para você, o que pode ajudar quando você precisar fazer coisas ainda mais irritantes (por exemplo, encadeie duas ssh chamadas):

$ printf '%q\n' "$mailcmd"
echo\ \"quotin\'\"\ \'this\ would\ be\ a\ \"nightmare\"\ indeed.\'\ \|\ mailx\ -s\ \"Anthony\'s\ Email\"\ -a\ attachment.txt\ -S\ from=\"myname@gmail\"\ destname@gmail

Como você pode ver, a cotação automatizada não é otimizada para poucas barras invertidas.

Incluindo variáveis locais

Se você precisar usar uma variável no comando, o ssh fornecerá um caso especial que funciona: ssh pode passar variáveis de ambiente especificadas pela opção SendEnv (client) e AcceptEnv option (server). Se você passar a variável de ambiente, o shell do lado remoto pode expandi-las como normal (e se você tiver "$ varname" no aqui-doc).

Além disso, a maneira mais fácil é omitir as aspas no heredoc, o que permitirá que as expansões aconteçam (embora isso signifique que você terá que escapar de $ onde você não quer isso):

$ var1="hello world"
$ read -r -d '' mailcmd <<CMD
echo "$var1" "\$var1"
CMD
$ echo "$mailcmd"
echo "hello world" "$var1"

Observe como estou usando CMD em vez de 'CMD' ; citando o marcador final como aquele desliga a expansão. Então, ao não citá-lo, conseguimos expansão. E "$var1" é expandido para hello world como esperado, mas colocando uma barra invertida na frente, a expansão pode ser evitada. Observe que toda a expansão está ativada, incluindo backtick e $(…) expansion. Observe também que var1 está apenas sendo substituído; o shell não está escapando, então isso não funcionaria se var1 contivesse uma aspa dupla (etc.). Esse é um lugar onde você pode usar% q:

$ var1='hello "world"'
$ read -r -d '' mailcmd <<CMD
echo $(printf '%q' "$var1") "\$var1"
CMD
$ echo "$mailcmd"
echo hello\ \"world\" "$var1"

Uma palavra de aviso: Se você transmitir dados que podem ser influenciados por um invasor, você deve ser muito cuidadoso. Qualquer pequeno erro ao escapar (ou uma definição diferente do que precisa ser escapado entre todos os shells envolvidos) pode se tornar uma falha arbitrária na execução do código. É mais fácil construir um sistema de passagem de dados mais robusto do que certificar-se de que o escape necessário está presente / correto. Um lote de vulnerabilidades de segurança tem escapado de falhas.

    
por 28.09.2017 / 17:20