扭矩 PBS 传递包含引号的环境变量
Torque PBS passing environment variables that contain quotes
我有一个 python 脚本。通常我会 运行 这样:
./make_graph data_directory "wonderful graph title"
我必须 运行 通过调度程序执行此脚本。我正在使用 -v 通过 qsub.
传递 python 脚本的参数
qsub make_graph.pbs -v ARGS="data_directory \"wonderful graph title\""
我尝试了很多 ', ", \" 转义的组合,但我就是做不好。 'wonderful graph title' 周围的引号总是丢失或损坏。
这是 pbs 脚本的摘录
if [ -z "${ARGS+xxx}" ]; then
echo "NO ARGS SPECIFIED!"
exit 1
fi
CMD="/path/make_graph $ARGS"
echo "CMD: $CMD"
echo "Job started on `hostname` at `date`"
${CMD}
将包含空格的字符串参数作为环境变量通过 qsub 传递的正确方法是什么?有一个更好的方法吗?也许这是一个更普遍的 bash 问题。
更新:此答案基于 SGE qsub
而不是 TORQUE qsub
,因此 CLI 有所不同。特别是,TORQUE qub
似乎不支持直接参数传递,因此第二种方法不起作用。
这主要是正确引用的问题,与Grid Engine提交本身关系不大。如果你只是想修复你当前的脚本,你应该使用 eval "${CMD}"
而不是 ${CMD}
。下面详细分析当你单独做 ${CMD}
时会发生什么(在分析中我们假设 path
没有什么好笑的):
您的 qsub
命令行已处理并删除了引号,因此传递的 ARGS
环境变量是 data_directory "wonderful graph title"
.
你做了CMD="/path/make_graph $ARGS"
,所以CMD
的值是/path/make_graph data_directory "wonderful graph title"
(我是在没有引号的情况下呈现字符串字面量,也就是字面值包含引号字符)。
你做到了 ${CMD}
。 Bash 对此进行参数扩展,相当于:
- 将
${CMD}
扩展为其值 /path/make_graph data_directory "wonderful graph title"
;
- 由于没有引用
${CMD}
,进行分词,所以最后命令行有五个词:/path/make_graph
、data_directory
、"wonderful
、graph
、title"
。最后四个被视为你的make_graph
的参数,这当然不是你想要的。
另一方面,如果您使用 eval "${CMD}"
,那么就像您在交互式 shell 中键入 /path/make_graph data_directory "wonderful graph title"
一样,这是所需的行为。
您应该在 Bash Reference Manual.
中阅读有关 eval
、参数扩展等的更多信息
更正后的脚本:
#!/usr/bin/env bash
[[ -z ${ARGS+xxx} ]] && { echo "NO ARGS SPECIFIED!" >&2; exit 1; }
CMD="/path/make_graph ${ARGS}"
echo "CMD: ${CMD}"
echo "Job started on $(hostname) at $(date)" # backticks are deprecated
eval "${CMD}"
顺便说一句,要测试它,您不需要将它提交给网格引擎;只是做
ARGS="data_directory \"wonderful graph title\"" bash make_graph.pbs
好的,我只是指出了错误并进行了修补。但它真的是 "proper way" 将参数传递给 Grid Engine 作业吗?不,我不这么认为。参数就是参数,不应与环境变量混淆。 qsub
允许您直接传递参数(qsub
概要:qsub [ options ] [ command | -- [ command_args ]]
),那么为什么在环境变量中对它们进行编码并最终担心引用?
这是编写提交脚本的更好方法:
#!/usr/bin/env bash
[[ $# == 0 ]] && { echo "NO ARGS SPECIFIED!" >&2; exit 1; }
CMD="/path/make_graph $@"
echo "CMD: ${CMD}"
echo "Job started on $(hostname) at $(date)" # backticks are deprecated
/path/make_graph "$@"
此处 "$@"
等同于 "" "" ...
— 忠实地按原样传递所有参数(请参阅 Bash 参考手册中的 relevant section)。
不幸的是,虽然执行的命令是正确的,但打印的命令可能没有正确引用。例如,如果你这样做
qsub make_graph.pbs data_directory "wonderful graph title"
那么执行的是make_graph.pbs data_directory "wonderful graph title"
,但是打印出来的CMD
是make_graph.pbs data_directory wonderful graph title
。据我所知,没有简单的方法来解决这个问题,因为无论如何进行分词,引号总是从参数中删除。如果打印的命令对你来说真的很重要,有两种解决方法:
使用专用的"shell escaper"(很容易自己写一个)在打印前引用参数;
使用另一种脚本语言,其中 shell 引用很容易获得,例如 Python (shlex.quote
) 或 Ruby (Shellwords.shellescape
).
我有一个 python 脚本。通常我会 运行 这样:
./make_graph data_directory "wonderful graph title"
我必须 运行 通过调度程序执行此脚本。我正在使用 -v 通过 qsub.
传递 python 脚本的参数qsub make_graph.pbs -v ARGS="data_directory \"wonderful graph title\""
我尝试了很多 ', ", \" 转义的组合,但我就是做不好。 'wonderful graph title' 周围的引号总是丢失或损坏。
这是 pbs 脚本的摘录
if [ -z "${ARGS+xxx}" ]; then
echo "NO ARGS SPECIFIED!"
exit 1
fi
CMD="/path/make_graph $ARGS"
echo "CMD: $CMD"
echo "Job started on `hostname` at `date`"
${CMD}
将包含空格的字符串参数作为环境变量通过 qsub 传递的正确方法是什么?有一个更好的方法吗?也许这是一个更普遍的 bash 问题。
更新:此答案基于 SGE qsub
而不是 TORQUE qsub
,因此 CLI 有所不同。特别是,TORQUE qub
似乎不支持直接参数传递,因此第二种方法不起作用。
这主要是正确引用的问题,与Grid Engine提交本身关系不大。如果你只是想修复你当前的脚本,你应该使用 eval "${CMD}"
而不是 ${CMD}
。下面详细分析当你单独做 ${CMD}
时会发生什么(在分析中我们假设 path
没有什么好笑的):
您的
qsub
命令行已处理并删除了引号,因此传递的ARGS
环境变量是data_directory "wonderful graph title"
.你做了
CMD="/path/make_graph $ARGS"
,所以CMD
的值是/path/make_graph data_directory "wonderful graph title"
(我是在没有引号的情况下呈现字符串字面量,也就是字面值包含引号字符)。你做到了
${CMD}
。 Bash 对此进行参数扩展,相当于:- 将
${CMD}
扩展为其值/path/make_graph data_directory "wonderful graph title"
; - 由于没有引用
${CMD}
,进行分词,所以最后命令行有五个词:/path/make_graph
、data_directory
、"wonderful
、graph
、title"
。最后四个被视为你的make_graph
的参数,这当然不是你想要的。
- 将
另一方面,如果您使用 eval "${CMD}"
,那么就像您在交互式 shell 中键入 /path/make_graph data_directory "wonderful graph title"
一样,这是所需的行为。
您应该在 Bash Reference Manual.
中阅读有关eval
、参数扩展等的更多信息
更正后的脚本:
#!/usr/bin/env bash
[[ -z ${ARGS+xxx} ]] && { echo "NO ARGS SPECIFIED!" >&2; exit 1; }
CMD="/path/make_graph ${ARGS}"
echo "CMD: ${CMD}"
echo "Job started on $(hostname) at $(date)" # backticks are deprecated
eval "${CMD}"
顺便说一句,要测试它,您不需要将它提交给网格引擎;只是做
ARGS="data_directory \"wonderful graph title\"" bash make_graph.pbs
好的,我只是指出了错误并进行了修补。但它真的是 "proper way" 将参数传递给 Grid Engine 作业吗?不,我不这么认为。参数就是参数,不应与环境变量混淆。 qsub
允许您直接传递参数(qsub
概要:qsub [ options ] [ command | -- [ command_args ]]
),那么为什么在环境变量中对它们进行编码并最终担心引用?
这是编写提交脚本的更好方法:
#!/usr/bin/env bash
[[ $# == 0 ]] && { echo "NO ARGS SPECIFIED!" >&2; exit 1; }
CMD="/path/make_graph $@"
echo "CMD: ${CMD}"
echo "Job started on $(hostname) at $(date)" # backticks are deprecated
/path/make_graph "$@"
此处 "$@"
等同于 "" "" ...
— 忠实地按原样传递所有参数(请参阅 Bash 参考手册中的 relevant section)。
不幸的是,虽然执行的命令是正确的,但打印的命令可能没有正确引用。例如,如果你这样做
qsub make_graph.pbs data_directory "wonderful graph title"
那么执行的是make_graph.pbs data_directory "wonderful graph title"
,但是打印出来的CMD
是make_graph.pbs data_directory wonderful graph title
。据我所知,没有简单的方法来解决这个问题,因为无论如何进行分词,引号总是从参数中删除。如果打印的命令对你来说真的很重要,有两种解决方法:
使用专用的"shell escaper"(很容易自己写一个)在打印前引用参数;
使用另一种脚本语言,其中 shell 引用很容易获得,例如 Python (
shlex.quote
) 或 Ruby (Shellwords.shellescape
).