Estou tentando implementar um tipo de mecanismo de execução a seco para o meu script e enfrentando o problema de aspas sendo retiradas quando um comando é passado como argumento para uma função e resultando em comportamento inesperado.
dry_run () {
echo "$@"
#printf '%q ' "$@"
if [ "$DRY_RUN" ]; then
return 0
fi
"$@"
}
email_admin() {
echo " Emailing admin"
dry_run su - $target_username -c "cd $GIT_WORK_TREE && git log -1 -p|mail -s '$mail_subject' $admin_email"
echo " Emailed"
}
A saída é:
su - webuser1 -c cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com
Esperado:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' [email protected]"
Com printf ativado em vez de eco:
su - webuser1 -c cd\ /home/webuser1/public_html\ \&\&\ git\ log\ -1\ -p\|mail\ -s\ \'Git\ deployment\ on\ webuser1\'\ user@domain.com
Resultado:
su: invalid option -- 1
Esse não deve ser o caso se as aspas permanecerem onde foram inseridas. Eu também tentei usar "eval", não há muita diferença. Se eu remover a chamada dry_run em email_admin e executar o script, ele funcionará muito bem.
Respostas:
Tente usar em
\"
vez de apenas"
.fonte
"$@"
Deveria trabalhar. De fato, funciona para mim neste caso de teste simples:Resultado:
Editado para adicionar: a saída de
echo $@
está correta. O"
é um meta-caractere e não faz parte do parâmetro. Você pode provar que está funcionando corretamente adicionandoecho $5
adry_run()
. Ele produzirá tudo depois-c
fonte
Este não é um problema trivial. O Shell executa a remoção de cotação antes de chamar a função, portanto, não há como a função recriar as cotações exatamente como você as digitou.
No entanto, se você quiser imprimir uma sequência que pode ser copiada e colada para repetir o comando, há duas abordagens diferentes que você pode seguir:
eval
e passe essa sequência paradry_run
dry_run
antes de imprimirUsando
eval
Veja como você pode usar
eval
para imprimir exatamente o que é executado:Resultado:
Observe a quantidade louca de citações - você tem um comando dentro de um comando, que fica feio rapidamente. Cuidado: o código acima terá problemas se suas variáveis contiverem espaços em branco ou caracteres especiais (como aspas).
Citando caracteres especiais
Essa abordagem permite que você escreva código de forma mais natural, mas a saída é mais difícil para os humanos lerem devido à maneira rápida e suja de
shell_quote
ser implementada:Resultado:
Você pode melhorar a legibilidade da saída alterando
shell_quote
para caracteres especiais de escape com barra invertida em vez de agrupar tudo entre aspas simples, mas é difícil fazer isso corretamente.Se você fizer a
shell_quote
abordagem, poderá construir o comando para transmitir desu
uma maneira mais segura. O seguinte funcionaria mesmo se${GIT_WORK_TREE}
,${mail_subject}
ou${admin_email}
contivesse caracteres especiais (aspas simples, espaços, asteriscos, ponto e vírgula, etc.):Resultado:
fonte
Isso é complicado, você pode tentar esta outra abordagem que já vi:
Dessa forma, você apenas define DRY_RUN como em branco ou "echo" na parte superior do seu script e ele faz ou apenas faz eco.
fonte
Bom desafio :) Deve ser "fácil" se você bash recente o suficiente para apoiar
$LINENO
e$BASH_SOURCE
Aqui está minha primeira tentativa, esperando que atenda às suas necessidades:
fonte