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:
- Cree una cadena de comando para ejecutar
eval
y pase esa cadena adry_run
- Cite los caracteres especiales del comando
dry_run
antes de imprimir
Utilizando eval
Aquí le mostramos cómo podría usar eval
para imprimir exactamente lo que se ejecuta:
dry_run() {
printf '%s\n' "$1"
[ -z "${DRY_RUN}" ] || return 0
eval "$1"
}
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:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"
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 :
# This function prints each argument wrapped in single quotes
# (separated by spaces). Any single quotes embedded in the
# arguments are escaped.
#
shell_quote() {
# run in a subshell to protect the caller's environment
(
sep=''
for arg in "$@"; do
sqesc=$(printf '%s\n' "${arg}" | sed -e "s/'/'\\\\''/g")
printf '%s' "${sep}'${sqesc}'"
sep=' '
done
)
}
dry_run() {
printf '%s\n' "$(shell_quote "$@")"
[ -z "${DRY_RUN}" ] || return 0
"$@"
}
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:
'su' '-' 'webuser1' '-c' 'cd /home/webuser1/public_html && git log -1 -p|mail -s '\''Git deployment on webuser1'\'' user@domain.com'
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 de su
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.):
email_admin() {
echo " Emailing admin"
cmd=$(
shell_quote cd "${GIT_WORK_TREE}"
printf '%s' ' && git log -1 -p | '
shell_quote mail -s "${mail_subject}" "${admin_email}"
)
dry_run su - "${target_username}" -c "${cmd}"
echo " Emailed"
}
Salida:
'su' '-' 'webuser1' '-c' ''\''cd'\'' '\''/home/webuser1/public_html'\'' && git log -1 -p | '\''mail'\'' '\''-s'\'' '\''Git deployment on webuser1'\'' '\''user@domain.com'\'''