이것은 사소한 문제가 아닙니다. 셸은 함수를 호출하기 전에 따옴표 제거를 수행하므로 사용자가 입력 한대로 따옴표를 정확하게 다시 만들 수있는 방법은 없습니다.
그러나 명령을 반복하기 위해 복사하여 붙여 넣을 수있는 문자열을 인쇄하려면 두 가지 방법을 사용할 수 있습니다.
- 실행할 명령 문자열을 작성하고
eval
해당 문자열을dry_run
dry_run
인쇄하기 전에 명령의 특수 문자 인용
사용 eval
eval
실행되는 내용을 정확하게 인쇄 하는 방법은 다음과 같습니다 .
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"
}
산출:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"
따옴표의 미친 양에 주목하십시오-당신은 명령 안에 명령 안에 명령이 있고, 이것은 추악하게 빠릅니다. 주의 사항 : 변수에 공백이나 따옴표와 같은 특수 문자가 포함되어 있으면 위의 코드에 문제가 있습니다.
인용 특수 문자
이 접근 방식을 사용하면 코드를보다 자연스럽게 작성할 수 있지만 더 빠르고 더러워진 방식으로 인해 사람이 읽기 어려운 결과가 나옵니다 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"
}
산출:
'su' '-' 'webuser1' '-c' 'cd /home/webuser1/public_html && git log -1 -p|mail -s '\''Git deployment on webuser1'\'' user@domain.com'
shell_quote
모든 것을 작은 따옴표로 묶지 않고 백 슬래시 이스케이프 특수 문자 로 변경하여 출력의 가독성을 향상시킬 수 있지만 올바르게 수행하기는 어렵습니다.
이 방법을 사용하면보다 안전한 방식으로 shell_quote
전달할 명령을 구성 할 수 있습니다 su
. 다음은 작동하더라도 것 ${GIT_WORK_TREE}
, ${mail_subject}
또는 ${admin_email}
특수 문자 (작은 따옴표, 공백, 별표, 세미콜론 등)을 포함 :
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"
}
산출:
'su' '-' 'webuser1' '-c' ''\''cd'\'' '\''/home/webuser1/public_html'\'' && git log -1 -p | '\''mail'\'' '\''-s'\'' '\''Git deployment on webuser1'\'' '\''user@domain.com'\'''