如何在bash中编写一个函数(我可以依赖它是v4 +),那么,给定构成具有可能环境覆盖的命令的单词,在当前shell中执行此命令?
例如,给定
f cd src
f CXX="ccache gcc" make -k XOPTIONS="--test1 --test2"
函数f
与在shell脚本中只有这些行而没有预先f
的情况大致相同?
一些不成功的尝试。
这会尝试将环境覆盖CXX="ccache gcc"
评估为命令。
f() { "$@" ; }
这会丢失所有参数的词语,在空格上打破单个参数词:
f() { eval "$@" ; }
这会处理环境覆盖,但在子shell中运行命令,因为env(1)不是内置的bash:
f() { env -- "$@" ; }
这个问题多次出现在SO和Unix SE上,但我从未见过它要求支持所有三个重要部分,即:环境覆盖;在当前shell中执行;并正确处理包含空格的参数(以及对bash特有的词汇特征的其他字符)。
我可能会使用的一件事是环境覆盖很少与内置版本一起使用(但是v。IFS= read...
),因此我可以基于{"@" ;
和eval -- "@" ;
模式进行选择{1}}在语法上是一个变量赋值。但同样,这并不像在其中发现$1
那么简单,因为等号可能被引用为命令的一部分,尽管这不太可能是理智的。尽管如此,我通常更喜欢正确的代码来大多数正确的代码,这种方法有两个连续的信念飞跃。
解决一个可能的问题为什么我需要一个复制shell 的默认行为的函数("只需删除 =
"):实际上,f
更复杂,只是运行命令,在几十个位置实现脚本中重复的模式;这只是我无法做到的部分。
答案 0 :(得分:2)
如果你能让eval
正确引用你的论据,它应该有效。为此,您可以使用%q
的{{1}}格式规范,其工作方式如下:
printf
这会产生类似
的功能$ printf '%q ' CXX="ccache gcc" make -k XOPTIONS="--test1 --test2"
CXX=ccache\ gcc make -k XOPTIONS=--test1\ --test2
请注意,这会在命令末尾附加一个额外的空格,但这不应该受到伤害。
答案 1 :(得分:0)
棘手。你可以这样做,但它会污染shell的环境:
f() {
# process any leading "var=value" assignments
while [[ $1 == ?*=* ]]; do
declare -x "$1"
shift
done
"$@"
}
刚做了一个快速测试:在函数中声明的env变量仍然是函数范围的本地变量,并且实际上不会污染脚本的环境。
$ f() {
declare -x FOO=bar
sh -c 'echo subshell FOO=$FOO'
echo function FOO=$FOO
}
$ unset foo
$ f
subshell FOO=bar
function FOO=bar
$ echo main shell FOO=$FOO
main shell FOO=