Estoy tratando de implementar un tipo de mecanismo de ejecución en seco para mi script y enfrento el problema de que las comillas se eliminen cuando se pasa un comando como argumento a una función y resulta en un comportamiento 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"
}
Salida es:
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]"
Con printf habilitado en lugar de echo:
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
Ese no debería ser el caso si las comillas permanecieran donde se insertaron. También he intentado usar "eval", no hay mucha diferencia. Si elimino la llamada dry_run en email_admin y luego ejecuto el script, funciona muy bien.
Respuestas:
Intenta usar en
\"
lugar de solo"
.fuente
"$@"
Deberia trabajar. De hecho, me funciona en este caso de prueba simple:Salida:
Editado para agregar: la salida de
echo $@
es correcta. El"
es un metacarácter y no forma parte del parámetro. Puede probar que funciona correctamente agregandoecho $5
adry_run()
. Producirá todo después-c
fuente
Este no es un problema trivial. Shell realiza la eliminación de comillas antes de llamar a la función, por lo que no hay forma de que la función pueda recrear las comillas exactamente como las escribió.
Sin embargo, si solo desea poder imprimir una cadena que se puede copiar y pegar para repetir el comando, hay dos enfoques diferentes que puede tomar:
eval
y pase esa cadena adry_run
dry_run
antes de imprimirUtilizando
eval
Aquí le mostramos cómo podría usar
eval
para imprimir exactamente lo que se ejecuta:Salida:
Tenga en cuenta la cantidad loca de citas: tiene un comando dentro de un comando dentro de un comando, que se pone feo rápidamente. Cuidado: el código anterior tendrá problemas si sus variables contienen espacios en blanco o caracteres especiales (como comillas).
Citando personajes especiales
Este enfoque le permite escribir código de forma más natural, pero la salida es más difícil de leer para los humanos debido a que
shell_quote
se implementa la forma rápida y sucia :Salida:
Puede mejorar la legibilidad de la salida cambiando
shell_quote
a caracteres especiales de barra invertida en lugar de envolver todo entre comillas simples, pero es difícil hacerlo correctamente.Si realiza el
shell_quote
enfoque, puede construir el comando para pasar desu
una manera más segura. Lo siguiente funcionaría incluso si${GIT_WORK_TREE}
,${mail_subject}
o${admin_email}
contuviera caracteres especiales (comillas simples, espacios, asteriscos, punto y coma, etc.):Salida:
fuente
Eso es complicado, puedes probar este otro enfoque que he visto:
de esa manera, simplemente configura DRY_RUN en blanco o "echo" en la parte superior de su script y lo hace o simplemente hace eco.
fuente
Bonito desafío :) Debería ser "fácil" si tienes bash lo suficientemente reciente como para soportar
$LINENO
y$BASH_SOURCE
Aquí está mi primer intento, esperando que se adapte a sus necesidades:
fuente