[英]An escaping of the variable within bash script
My bash script writes an another bash script using printf. 我的bash脚本使用printf编写了另一个bash脚本。
printf "#!/bin/bash
HOME=${server}
file=gromacs*
file_name=\$(basename "\${file}")
date=\$(date +"\%m_\%d_\%Y")
for sim in \${HOME}/* ; do
if [[ -d \$sim ]]; then
simulation=$(basename "\$sim")
pushd \${sim}
cp \$file \${server}/\${results}/\${file_name}.\${simulation}.\${date}
echo "\${file_name}\ from\ \${simulation}\ has\ been\ collected!"
popd
fi
done" > ${output}/collecter.sh
Here there is a problem in escappiong of the elements within date variable 这里的日期变量中的元素的转义有问题
date=\$(date +"\%m_\%d_\%Y")
where the below part did not work properly 以下部分无法正常工作的地方
"\%m_\%d_\%Y"
it results in incomplete of a new bash script produced by printf. 它导致由printf生成的新bash脚本不完整。
How it should be fixed? 应该如何解决?
Thanks! 谢谢!
Use a quoted heredoc. 使用带引号的heredoc。
{
## print the header, and substitute our own value for HOME
printf '#!/bin/bash\nHOME=%q\n' "$server"
## EVERYTHING BELOW HERE UNTIL THE EOF IS LITERAL
cat <<'EOF'
file=( gromacs* )
(( ${#file[@]} == 1 )) && [[ -e $file ]] || {
echo "ERROR: Exactly one file starting with 'gromacs' should exist" >&2
exit 1
}
file_name=$(basename "${file}")
date=$(date +"%m_%d_%Y")
for sim in "$HOME"/* ; do
if [[ -d $sim ]]; then
simulation=$(basename "$sim")
(cd "${sim}" && exec cp "$file" "${server}/${results}/${file_name}.${simulation}.${date}")
echo "${file_name} from ${simulation} has been collected!"
fi
done
EOF
} >"${output}/collecter.sh"
Note: 注意:
cat <<'EOF'
), no substitutions are performed, so no escaping is needed . cat <<'EOF'
)内, 不会执行任何替换,因此不需要转义 。 We're thus able to write our code exactly as we want it to exist in the generated file. printf %q
to escape values in such a way as to evaluate back to their original values. printf %q
对值进行转义,以便求回到原始值。 Otherwise, a variable containing $(rm -rf ~)
could cause the given command to be run (if it were substituted inside literal single quotes, making the contents $(rm -rf ~)'$(rm -rf ~)'
would escape them). $(rm -rf ~)
的变量可能会使给定命令运行(如果在文字单引号内将其替换,则使内容$(rm -rf ~)'$(rm -rf ~)'
逃脱他们)。 file=( gromacs* )
makes the storage of the result in an array explicit, and the following code checks for both the case where we have more than one result, and the case where our result is the original glob expression (meaning no matches existed). file=( gromacs* )
使结果显式存储在数组中,下面的代码将检查是否有多个结果,以及结果是否是原始glob表达式(表示否)。已存在匹配项)。 "$HOME"/*
, not $HOME/*
-- otherwise you'll have problems whenever a user has a home directory containing whitespace (and yes, this does happen -- consider Windows-derived platforms where you have /Users/Firstname Lastname
, or sites where you've mounted a volume for home directories off same). "$HOME"/*
,而不是$HOME/*
-否则,每当用户有一个包含空格的主目录时,您都会遇到问题(是的,这确实会发生–考虑您拥有/Users/Firstname Lastname
Windows派生平台/Users/Firstname Lastname
,或者您已在其中装入主目录卷的站点)。 pushd
and popd
are an interactive extension, as opposed to a tool intended for writing scripts. pushd
和popd
是一个交互式扩展。 Since spawning an external program (such as cp
) involves a fork() operation, and any directory change inside a subshell terminates when that subshell does, you can avoid any need for them by spawning a subshell, cd
'ing within that subshell, and then using the exec
builtin to replace the subshell's PID with that of cp
, thus preventing the fork
that would otherwise have taken place to allow cp
to be started in a separate process from the shell acting as its parent. cp
)涉及fork()操作,并且在该子Shell发生作用时,该子Shell中的任何目录更改都会终止,因此可以通过产生一个子Shell,在该子Shell中进行cd
来避免对它们的任何需要,并且然后使用exec
内置exec
用cp
替换子shell的PID,从而防止发生fork
,否则将允许cp
在与作为其父项的shell分开的进程中启动。 You have to escapes in printf
with esscaps, eg: 您必须使用esscaps在
printf
中转义,例如:
date=\$(date +"%%m_%%d_%%Y")
should print date=\\$(date +"%m_%d_%Y")
. 应该打印
date=\\$(date +"%m_%d_%Y")
。 But you should avoid using printf
, because you don't use it's capabilities. 但是您应该避免使用
printf
,因为您没有使用它的功能。 Instead you could cat the string to the file: 相反,您可以将字符串指向文件:
cat > ${output}/collecter.sh <<'END'
HOME=${server}
...
done
END
This would allow you to avoid many escapes, and make the code more readable. 这将使您避免许多转义,并使代码更具可读性。
尝试这个
date=\$(date +\"%%m_%%d_%%Y\")"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.