我的 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
这里存在日期变量中元素转义的问题
date=\$(date +"\%m_\%d_\%Y")
以下部分无法正常工作的地方
"\%m_\%d_\%Y"
它会导致 printf 生成的新 bash 脚本不完整。
应该如何修复呢?
Thanks!
使用引用的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:
- 在引用的heredoc中(
cat <<'EOF'
), 不执行替换,因此不需要转义。因此,我们能够完全按照我们希望生成的文件中存在的方式编写代码。
-
生成代码时,使用
printf %q
以求值返回其原始值的方式转义值。否则,一个变量包含$(rm -rf ~)
可能会导致运行给定的命令(如果将其替换为文字单引号,则内容$(rm -rf ~)'$(rm -rf ~)'
会逃脱他们)。
-
全局扩展返回结果列表;存储结果的正确数据类型是数组,而不是字符串。 Thus,
file=( gromacs* )
使结果在数组中的存储显式化,并且以下代码检查我们有多个结果的情况以及我们的结果是原始 glob 表达式的情况(意味着不存在匹配项)。
-
所有扩展都需要加引号以防止字符串分割。这意味着
"$HOME"/*
, not $HOME/*
-- 否则,只要用户的主目录包含空格,您就会遇到问题(是的,这种情况确实会发生 -- 考虑 Windows 派生平台,其中您有/Users/Firstname Lastname
,或您已安装主目录卷的站点)。
-
pushd
and popd
是一个交互式扩展,而不是用于编写脚本的工具。由于产生了外部程序(例如cp
)涉及 fork() 操作,并且子 shell 内的任何目录更改都会在该子 shell 执行时终止,您可以通过生成子 shell 来避免对它们的任何需要,cd
' 在该子 shell 中,然后使用exec
内置的子 shell 的 PID 替换为cp
,从而防止fork
否则的话就会发生cp
在与作为其父级的 shell 分开的进程中启动。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)