Sho*_*ibi 10 scripting linux shell bash
我正在尝试为我的脚本实现一种空运行的机制,并面临当命令作为参数传递给函数并导致意外行为时引号被剥离的问题。
dry_run () {
echo "$@"
#printf '%q ' "$@"
if [ "$DRY_RUN" ]; then
return 0
fi
"$@"
}
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"
}
Run Code Online (Sandbox Code Playgroud)
输出是:
su - webuser1 -c cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com
Run Code Online (Sandbox Code Playgroud)
预期的:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"
Run Code Online (Sandbox Code Playgroud)
启用 printf 而不是回声:
su - webuser1 -c cd\ /home/webuser1/public_html\ \&\&\ git\ log\ -1\ -p\|mail\ -s\ \'Git\ deployment\ on\ webuser1\'\ user@domain.com
Run Code Online (Sandbox Code Playgroud)
结果:
su: invalid option -- 1
Run Code Online (Sandbox Code Playgroud)
如果引号保留在插入的位置,情况就不应该如此。我也试过使用“eval”,差别不大。如果我删除 email_admin 中的 dry_run 调用,然后运行脚本,效果很好。
"$@"应该管用。事实上,它在这个简单的测试用例中对我有用:
dry_run()
{
"$@"
}
email_admin()
{
dry_run su - foo -c "cd /var/tmp && ls -1"
}
email_admin
Run Code Online (Sandbox Code Playgroud)
输出:
./foo.sh
a
b
Run Code Online (Sandbox Code Playgroud)
编辑添加:输出echo $@是正确的。该"是元字符,而不是参数的一部分。您可以通过添加echo $5到来证明它正常工作dry_run()。之后会输出所有内容-c
这不是一个小问题。Shell 在调用函数之前执行引号删除,因此函数无法完全按照您键入的方式重新创建引号。
但是,如果您只想打印出可以复制和粘贴以重复命令的字符串,则可以采用两种不同的方法:
eval并将该字符串传递给dry_rundry_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"
}
Run Code Online (Sandbox Code Playgroud)
输出:
su - webuser1 -c "cd /home/webuser1/public_html && git log -1 -p|mail -s 'Git deployment on webuser1' user@domain.com"
Run Code Online (Sandbox Code Playgroud)
注意大量的引用——你在一个命令中的一个命令中有一个命令,这很快就会变得丑陋。注意:如果您的变量包含空格或特殊字符(如引号),则上述代码会出现问题。
这种方法使您能够更自然地编写代码,但由于实现了快速而肮脏的方式,因此输出对于人类来说更难阅读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"
}
Run Code Online (Sandbox Code Playgroud)
输出:
'su' '-' 'webuser1' '-c' 'cd /home/webuser1/public_html && git log -1 -p|mail -s '\''Git deployment on webuser1'\'' user@domain.com'
Run Code Online (Sandbox Code Playgroud)
您可以通过更改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"
}
Run Code Online (Sandbox Code Playgroud)
输出:
'su' '-' 'webuser1' '-c' ''\''cd'\'' '\''/home/webuser1/public_html'\'' && git log -1 -p | '\''mail'\'' '\''-s'\'' '\''Git deployment on webuser1'\'' '\''user@domain.com'\'''
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
26630 次 |
| 最近记录: |