当Bash函数是管道的一部分时,它会失败

时间:2012-07-10 07:59:45

标签: bash pipe bash-function

这是为了简化我遇到的问题。 我定义了一个设置变量的函数,这在这种情况下有效:

$ function myfunc { res="ABC" ; }
$ res="XYZ"
$ myfunc
$ echo $res
    ABC

因此调用myfunc改变了res。但是:

$ res="XYZ"
$ myfunc | echo
$ echo $res
    XYZ

因此,当myfunc是管道的一部分时,值不会改变。 即使涉及管道,如何使myfunc以我想要的方式工作?

(在真实的剧本中,“myfunc”当然会做一些更精细的事情,管道的另一面有一个zenity进度对话而不是一个无意义的回声)

由于

2 个答案:

答案 0 :(得分:4)

这在Unix上是不可能的。要更好地理解这一点,您需要知道变量是什么。 Bash使用所有已定义的变量保留两个内部表。一个是当前shell的本地变量。您可以使用set name=valuename=value创建这些广告。这些是当地的过程;创建新进程时,它们不会被继承。

要将变量导出到新的子进程,必须使用export name将其导出。这告诉bash“我希望孩子们看到这个变量的价值”。这是一个安全功能。

当你在bash中调用一个函数时,它在当前shell的上下文中执行,因此它可以访问和修改所有变量。

但是管道是与I / O管道连接的进程列表。这意味着你的函数在shell中执行,只有{shell}的输出对echo可见。

即使在myfunc中导出也无效,因为导出仅适用于您执行导出的shell启动的进程,而echo由与myfunc相同的shell启动:< / p>

bash
 +-- myfunc
 +-- echo

echo不是myfunc的孩子。

解决方法:

  1. 将变量写入文件
  2. 使用更复杂的输出格式,如XML或多行,其中第一行输出始终是变量,实际输出来自下一行。

答案 1 :(得分:4)

正如@Aaron所说,问题是由子shell中运行的函数引起的。但是有一种方法可以在bash中避免这种情况,使用进程替换而不是管道:

myfunc > >(echo)

这与管道的作用大致相同,但myfunc在主shell而不是子进程中运行。请注意,这是一个仅限bash的功能,并且必须使用#!/ bin / bash作为你的shebang才能工作。