Dies ist kein triviales Problem. Shell führt vor dem Aufrufen der Funktion eine Anführungszeichenentfernung durch, sodass die Funktion die Anführungszeichen auf keinen Fall genau so neu erstellen kann, wie Sie sie eingegeben haben.
Wenn Sie jedoch nur eine Zeichenfolge ausdrucken möchten, die kopiert und eingefügt werden kann, um den Befehl zu wiederholen, können Sie zwei verschiedene Ansätze wählen:
- Erstellen Sie eine Befehlszeichenfolge, über die ausgeführt werden soll,
eval
und übergeben Sie diese Zeichenfolge andry_run
- Geben Sie
dry_run
vor dem Drucken die Sonderzeichen des Befehls an
Verwenden von eval
So können Sie eval
genau drucken, was ausgeführt wird:
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"
}
Ausgabe:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"
Beachten Sie die verrückte Menge an Zitaten - Sie haben einen Befehl innerhalb eines Befehls innerhalb eines Befehls, der schnell hässlich wird. Achtung: Der obige Code hat Probleme, wenn Ihre Variablen Leerzeichen oder Sonderzeichen (wie Anführungszeichen) enthalten.
Sonderzeichen zitieren
Dieser Ansatz ermöglicht es Ihnen, Code natürlicher zu schreiben, aber die Ausgabe ist für Menschen schwieriger zu lesen, da die schnelle und schmutzige Methode shell_quote
implementiert ist:
# 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"
}
Ausgabe:
'su' '-' 'webuser1' '-c' 'cd /home/webuser1/public_html && git log -1 -p|mail -s '\''Git deployment on webuser1'\'' user@domain.com'
Sie können die Lesbarkeit der Ausgabe verbessern, indem Sie shell_quote
zu Sonderzeichen mit umgekehrten Schrägstrichen wechseln , anstatt alles in einfache Anführungszeichen zu setzen. Dies ist jedoch schwierig.
Wenn Sie den shell_quote
Ansatz ausführen, können Sie den Befehl so konstruieren, dass su
er sicherer übergeben wird. Die folgende funktionieren würde, auch wenn ${GIT_WORK_TREE}
, ${mail_subject}
oder ${admin_email}
enthalten sind Sonderzeichen (Apostrophe, Leerzeichen, Sternchen, Semikolons, 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"
}
Ausgabe:
'su' '-' 'webuser1' '-c' ''\''cd'\'' '\''/home/webuser1/public_html'\'' && git log -1 -p | '\''mail'\'' '\''-s'\'' '\''Git deployment on webuser1'\'' '\''user@domain.com'\'''