bash脚本中变量的转义 [英] An escaping of the variable within bash script

查看:397
本文介绍了bash脚本中变量的转义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的bash脚本使用printf编写了另一个bash脚本.

My bash script writes an another bash script using printf.

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")

以下部分无法正常工作

"\%m_\%d_\%Y"

它导致由printf生成的新bash脚本不完整.

it results in incomplete of a new bash script produced by printf.

应如何解决?

谢谢!

推荐答案

使用带引号的heredoc.

Use a quoted 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 ~)'可以转义).
  • Glob扩展返回结果列表;存储结果的正确数据类型是数组,而不是字符串.因此,file=( gromacs* )使结果在数组中的存储方式明确,下面的代码检查两种情况:不止一个结果,而且我们的结果是原始的glob表达式(表示不存在匹配项).
  • 所有扩展名都必须加引号,以防止字符串拆分.这表示"$HOME"/*,而不是$HOME/*-否则,只要用户的主目录包含空格(是的,的确会发生这种情况,请考虑使用/Users/Firstname Lastname的Windows衍生平台,或已为其安装主目录卷的站点.)
  • pushdpopd是交互式扩展,与用于编写脚本的工具相反.由于产生外部程序(例如cp)涉及fork()操作. ,并且子shell中的任何目录更改都在该子shell终止时终止,您可以通过生成子shell,在该子shell中使用cd,然后使用内置的exec替换该子shell的PID来避免对它们的任何需要cp的值,这样可以防止fork发生,否则将不允许cp在与作为其父级的shell分开的进程中启动.
  • Inside a quoted heredoc (cat <<'EOF'), no substitutions are performed, so no escaping is needed. We're thus able to write our code exactly as we want it to exist in the generated file.
  • When generating code, use printf %q to escape values in such a way as to evaluate back to their original values. 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).
  • Glob expansions return a list of results; the proper data type in which to store their results is an array, not a string. Thus, 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).
  • All expansions need to be quoted to prevent string-splitting. This means "$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).
  • pushd and popd are an interactive extension, as opposed to a tool intended for writing scripts. 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.

这篇关于bash脚本中变量的转义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆