繁体   English   中英

bash脚本中变量的转义

[英]An escaping of the variable within bash script

我的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脚本不完整。

应该如何解决?

谢谢!

使用带引号的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"

注意:

  • 在带引号的heredoc(目录cat <<'EOF' )内, 不会执行任何替换,因此不需要转义 因此,我们可以完全按照我们希望其在生成的文件中存在的方式编写代码。
  • 生成代码时,请使用printf %q对值进行转义,以便求回到原始值。 否则,包含$(rm -rf ~)的变量可能会使给定命令运行(如果在文字单引号内将其替换,则使内容$(rm -rf ~)'$(rm -rf ~)'逃脱他们)。
  • Glob扩展返回结果列表; 存储结果的适当数据类型是数组,而不是字符串。 因此, file=( gromacs* )使结果显式存储在数组中,下面的代码将检查是否有多个结果,以及结果是否是原始glob表达式(表示否)。已存在匹配项)。
  • 所有扩展都需要加引号,以防止字符串分割。 这意味着"$HOME"/* ,而不是$HOME/* -否则,每当用户有一个包含空格的主目录时,您都会遇到问题(是的,这确实会发生–考虑您拥有/Users/Firstname Lastname Windows派生平台/Users/Firstname Lastname ,或者您已在其中装入主目录卷的站点)。
  • 与用于编写脚本的工具相反, pushdpopd是一个交互式扩展。 由于派生外部程序(例如cp )涉及fork()操作,并且在该子Shell发生作用时,该子Shell中的任何目录更改都会终止,因此可以通过产生一个子Shell,在该子Shell中进行cd来避免对它们的任何需要,并且然后使用exec内置execcp替换子shell的PID,从而防止发生fork ,否则将允许cp在与作为其父项的shell分开的进程中启动。

您必须使用esscaps在printf中转义,例如:

date=\$(date +"%%m_%%d_%%Y")

应该打印date=\\$(date +"%m_%d_%Y") 但是您应该避免使用printf ,因为您没有使用它的功能。 相反,您可以将字符串指向文件:

cat > ${output}/collecter.sh <<'END'
HOME=${server}
...
done
END

这将使您避免许多转义,并使代码更具可读性。

尝试这个

date=\$(date +\"%%m_%%d_%%Y\")" 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM