Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 使用';评估';在函数中使用时产生的结果与在脚本中使用时不同_Bash - Fatal编程技术网

Bash 使用';评估';在函数中使用时产生的结果与在脚本中使用时不同

Bash 使用';评估';在函数中使用时产生的结果与在脚本中使用时不同,bash,Bash,假设在我当前的目录中有文件:a.1、a.2、b.1、b.2。 我在文件“x”中有此脚本: echo `eval echo "$1"` echo 'eval echo "$2"` 如果我这样做: > set -f; x a* b* 我得到: > a.1 a.2 > b.1 b.2 。。。这很好,我可以访问和扩展任何命令行参数(如键入的),并根据自己的喜好进行扩展 唉!如果我将脚本“x”的内容放在一个函数中,它将不再工作,通配符将拒绝展开。当然,我可以删除“set-f”,但是

假设在我当前的目录中有文件:a.1、a.2、b.1、b.2。 我在文件“x”中有此脚本:

echo `eval echo "$1"`
echo 'eval echo "$2"`
如果我这样做:

> set -f; x a* b*
我得到:

> a.1 a.2
> b.1 b.2
。。。这很好,我可以访问和扩展任何命令行参数(如键入的),并根据自己的喜好进行扩展

唉!如果我将脚本“x”的内容放在一个函数中,它将不再工作,通配符将拒绝展开。当然,我可以删除“set-f”,但是参数列表会扩展为“失控”,也就是说,我不知道“b*”参数从哪里开始,因为我不知道“a*”将扩展到多少个参数

我能在函数中实现上述功能吗?就这一点而言,为什么它的行为与脚本中的相同代码不同


谢谢

您最初的
设置-f
只影响当前的shell实例。启动脚本时,将启动一个新的shell,并且该shell已启用全局绑定。如果用函数替换脚本,函数将在shell的上下文中运行,其中
set-f
有效,因此不会发生全局绑定

实际上,你不需要禁用globbing来获得你想要的行为。您只需引用函数的参数:

myfunc()
{
    echo $1
    echo $2
}

myfunc "a.*" "b.*"
function x () { for arg in "$@" ; do echo $arg ; done ; }
x 'a.*' 'b.*' # prints a.1 a.2 on one line, b.1 b.2 on the next.

产生差异的原因是,当您将其放入一个单独的脚本
x
,并使用

x ...
然后,您将启动一个单独的Bash实例来运行脚本(也就是说,它相当于

bash x ...
),并且该单独的实例不会继承
set-f
设置,而当您将其放入shell函数中时,它会在同一个实例中运行

一种解决方案是放弃整个
set-f
方法,在调用函数时只引用参数:

myfunc()
{
    echo $1
    echo $2
}

myfunc "a.*" "b.*"
function x () { for arg in "$@" ; do echo $arg ; done ; }
x 'a.*' 'b.*' # prints a.1 a.2 on one line, b.1 b.2 on the next.
另一种解决方案是定义要在子shell中运行的函数(但仍在Bash的同一实例中),然后使用
set+f
取消该函数中的
set-f

set -f
function x () ( set +f ; for arg in "$@" ; do echo $arg ; done )
x a.* b.* # prints a.1 a.2 on one line, b.1 b.2 on the next.
(使用子shell的原因,即使用
(…)
而不是
{…}
的原因是,否则,
set+f
将“泄漏”函数调用。但这可能没问题吧?)

另一种解决方案是让函数调用新的Bash实例:

set -f
function x () { for arg in "$@" ; do bash -c "echo $arg" ; done ; }
x a.* b.* # prints a.1 a.2 on one line, b.1 b.2 on the next.

是的,我明白了,“地下室”就是区别。有很多想法需要考虑,非常感谢。我发现了另一个似乎有用的东西。虽然大脑麻木,但如果我只是在函数的顶部添加“set+f”,一切都很好。正如您所期望的,第一个“set-f”似乎停止了扩展,但是函数中的“set-f”允许“eval”完成它的工作,我得到了我想要的。。。但所有这些都是很有教育意义的。非常感谢。FWIW,所有这些痛苦都来自于我为常用命令(find、ls、grep等)制作的一些包装器。我的目标是创建一个标准化的语法,这样我就不必每五分钟运行一次手册页,这意味着我需要能够在自己的控制下展开命令行参数,以便我知道传递给“real”命令的是什么。@raydrews:为了澄清,子shell从其父级继承
set-f
设置;只有当您调用一个全新的Bash实例时,
set-f
设置才不会传入。是的,我知道我可以引用,但我尽量避免,因为我正在制作的这些包装是为了我经常使用的命令。打字经济才是关键。