Questo non è un problema banale. Shell esegue la rimozione delle virgolette prima di chiamare la funzione, quindi non c'è modo che la funzione possa ricreare le virgolette esattamente come le hai digitate.
Tuttavia, se vuoi solo essere in grado di stampare una stringa che può essere copiata e incollata per ripetere il comando, puoi adottare due diversi approcci:
- Costruire una stringa di comando da eseguire
eval
e passare quella stringa adry_run
- Cita i caratteri speciali del comando
dry_run
prima di stampare
utilizzando eval
Ecco come è possibile utilizzare eval
per stampare esattamente ciò che viene eseguito:
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"
}
Produzione:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"
Nota la folle quantità di preventivi: hai un comando all'interno di un comando all'interno di un comando, che diventa brutto rapidamente. Attenzione: il codice sopra riportato avrà problemi se le variabili contengono spazi bianchi o caratteri speciali (come virgolette).
Citando personaggi speciali
Questo approccio consente di scrivere il codice in modo più naturale, ma l'output è più difficile da leggere per gli umani a causa dell'implementazione del metodo rapido e sporco shell_quote
:
# 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"
}
Produzione:
'su' '-' 'webuser1' '-c' 'cd /home/webuser1/public_html && git log -1 -p|mail -s '\''Git deployment on webuser1'\'' user@domain.com'
Puoi migliorare la leggibilità dell'output cambiando shell_quote
in caratteri speciali di backslash invece di racchiudere tutto tra virgolette singole, ma è difficile farlo correttamente.
Se segui l' shell_quote
approccio, puoi costruire il comando a cui passare su
in modo più sicuro. I seguenti funzionerebbero anche se ${GIT_WORK_TREE}
, ${mail_subject}
o ${admin_email}
contenessero caratteri speciali (virgolette singole, spazi, asterischi, punti e virgola, ecc.):
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"
}
Produzione:
'su' '-' 'webuser1' '-c' ''\''cd'\'' '\''/home/webuser1/public_html'\'' && git log -1 -p | '\''mail'\'' '\''-s'\'' '\''Git deployment on webuser1'\'' '\''user@domain.com'\'''