背景:我正在编写一个包装脚本,该脚本处理将研究人员的工作发送到我们的计算集群(其中一个使用SLURM,另一个使用Torque / PBS)。它还必须替代一些分析软件(例如FSL)中包含的包装器脚本,以便它们可以直接与集群交互。
在用户端,该脚本将这样调用:
submit_job [arguments] <command to run>
对调度程序的调用已组合,<command to run>
应该以提交给调度程序的小脚本结尾。目前,这是这样实现的:
# In case of SLURM
sbatch <sbatch arguments> <<EOF
#!/usr/bin/env bash
srun "${@}"
EOF
但是,如果我仅使用${@}
,则不会保留引号。该命令可以包含引号(例如,带空格的路径),并且可以有多个用分号分隔的命令(但整个内容将用引号引起来)。我真的无法控制由使用它的人员和软件所带来的后果。
因此,如何从A(脚本参数)到B(变量)到C(heredoc)获取命令(可以包含引号,例如带空格的路径,以及可能有多个用分号分隔的命令),而不会造成混乱报价吗?
按照经常引用的FAQ entry中的建议,我使用Bash数组组装了调度程序命令,并且运行良好。但是,尽管我可以这样做:
#/usr/bin/env bash
run=( mkdir "foo bar" )
set -x
"${run[@]}"
set +x
并且目录foo bar
已创建,我不能这样做:
#/usr/bin/env bash
run=( mkdir "foo bar" )
/usr/bin/env bash <<EOF
set -x
$run[@]
"${run[@]}"
set +x
EOF
第一个创建目录foo
和bar
,因为发生了扩展,第二个创建并尝试运行mkdir foo bar
,但失败。
那我还有什么?
提前谢谢
答案 0 :(得分:2)
使用printf "%q"
转义参数。这是传递args的好方法。
#/usr/bin/env bash
run=(mkdir "foo bar")
/usr/bin/env bash <<EOF
set -x
${run[@]} # this expands into `mkdir foo bar`
$(printf "%q " "${run[@]}") # this expands into `mkdir foo\ bar`
set +x
EOF