在字符串中构建一个 shell 命令,以便以后可移植地执行

Posted

技术标签:

【中文标题】在字符串中构建一个 shell 命令,以便以后可移植地执行【英文标题】:Build a shell command in a string for later execution portably 【发布时间】:2017-09-23 02:26:49 【问题描述】:

我正在尝试在bashdash 中执行以下命令:

x="env PATH=\"$PATH:/dir with space\""
cmd="ls"
"$x" $cmd

这失败了

-bash: env PATH="/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/ X11/bin:/usr/local/git/bin:/usr/local/go/bin:/dir 带空格": 没有这样的文件或目录

注意以下工作:

env PATH="$PATH:/dir with space" $cmd

我分配给变量x env 的原因是因为它是$cmd 的更大命令包装器的一部分,这也是一个复杂的变量。

它比最初的例子更复杂。我有设置这些变量的逻辑,而不是每次都重复它们。最终调用如下所示:

path_value="$PATH"
invocation="env PATH=\"$path_value\" $other_val1 $other_val2"
base="python python_script.py --opt1=a,b,c script_args"
add_on="$base more_arg1 more_arg2"
"$invocation" $base

【问题讨论】:

你试过转义空格吗? 看一个更简单的例子:x="echo hello"; "$x" - 这将返回 echo hello: command not found - 尝试在 "$x" 周围不带引号的情况下运行它。 鉴于您在下面的评论中提到了一个子进程:您真的在使用 shell 代码构建命令行字符串吗?如果您在 Python 中构造字符串,则需要考虑不同的注意事项。 您可能根本不需要env。例如,PATH="$PATH:/dir with space" python arg1 arg2 使用修改后的 PATH 运行 python 【参考方案1】:

可以使用shell数组来存储和复用:

x=(env PATH="$PATH:/dir with space")
cmd="ls"
"$x[@]" "$cmd"

【讨论】:

这是最干净的解决方案 - 使用 shell 数组。 这是一个很好的解决方案。我必须添加一个警告,我在不支持 bash 数组或 的环境中使用它。 但您将其标记为bash。那是什么外壳? 它在各种平台上作为直接子进程调用运行,使用默认外壳。通常是 bash,但有时是 dash。 @JonathanAbrahams 在 POSIX shell 中没有好的、安全的方法可以做到这一点;这就是为什么这么多其他 shell 提供对数组的支持。【参考方案2】:

anubhava's helpful array-based bash answer 是最好的选择,如果你可以假设 only bash(最初似乎是这样)。

鉴于您还必须支持 dash,它几乎只支持 POSIX sh 功能,因此不能选择数组。

假设您完全控制或信任用于在字符串中构建命令行的值,您可以使用eval,其中should generally be avoided:

path_value="$PATH"
invocation="env PATH=\"$path_value\" $other_val1 $other_val2"
base="python python_script.py --opt1=a,b,c script_args"
add_on="$base more_arg1 more_arg2"

eval "$invocation $add_on"

【讨论】:

以上是关于在字符串中构建一个 shell 命令,以便以后可移植地执行的主要内容,如果未能解决你的问题,请参考以下文章

shell基础知识总结

如何在 shell 命令中发送 Jenkins 版本号作为参数,该命令将在构建结束后执行

如何执行 shell 命令来填充 Jenkins 动态选择参数插件

为 PERL 脚本构建 CLI 参数的 Shell 脚本

linux命令 EOF

linux中比较实用的shell脚本