Ce n'est pas un problème trivial. Shell effectue la suppression des guillemets avant d'appeler la fonction, il n'y a donc aucun moyen que la fonction puisse recréer les guillemets exactement comme vous les avez tapés.
Cependant, si vous voulez simplement pouvoir imprimer une chaîne qui peut être copiée et collée pour répéter la commande, vous pouvez adopter deux approches différentes:
- Créez une chaîne de commande à exécuter
eval
et transmettez-la àdry_run
- Citez les caractères spéciaux de la commande
dry_run
avant d'imprimer
En utilisant eval
Voici comment vous pouvez utiliser eval
pour imprimer exactement ce qui est exécuté:
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"
}
Production:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"
Notez la quantité folle de citations - vous avez une commande dans une commande dans une commande, qui devient laide rapidement. Attention: le code ci-dessus aura des problèmes si vos variables contiennent des espaces ou des caractères spéciaux (comme des guillemets).
Citation de caractères spéciaux
Cette approche vous permet d'écrire du code plus naturellement, mais la sortie est plus difficile à lire pour les humains car la méthode rapide et sale shell_quote
est implémentée:
# 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"
}
Production:
'su' '-' 'webuser1' '-c' 'cd /home/webuser1/public_html && git log -1 -p|mail -s '\''Git deployment on webuser1'\'' user@domain.com'
Vous pouvez améliorer la lisibilité de la sortie en shell_quote
remplaçant les caractères spéciaux par une barre oblique inverse au lieu de tout mettre entre guillemets simples, mais c'est difficile à faire correctement.
Si vous faites l' shell_quote
approche, vous pouvez construire la commande à laquelle passer de su
manière plus sûre. Ce qui suit fonctionnerait même si ${GIT_WORK_TREE}
, ${mail_subject}
ou ${admin_email}
contenait des caractères spéciaux (guillemets simples, des espaces, des astérisques, des points - virgules, 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"
}
Production:
'su' '-' 'webuser1' '-c' ''\''cd'\'' '\''/home/webuser1/public_html'\'' && git log -1 -p | '\''mail'\'' '\''-s'\'' '\''Git deployment on webuser1'\'' '\''user@domain.com'\'''