awk 中的协进程和双向管道

awk 中的协进程和双向管道

我试图理解command | getline var和之间的区别command |& getline var。我通常应该使用哪一种?一直在阅读有关协进程和双向管道的内容,但需要一些解释,因为事情变得非常混乱。

实际上,我正在使用

kmd=sprintf("%s%d\n", "tput bold; tput setaf ", knum)
tseq[knam] = ( (kmd | getline outp) > 0 ? outp : "<" knam ">" )
close(kmd)

这里的协进程是什么?是不是在使用tput。我认为代码中只有一种单向管道通信。使用 会有什么好处kmd |& getline outp,我应该使用后者吗?

答案1

您问题中的代码中没有协进程 - 您所拥有的只是生成一个要调用的子 shell tput,然后使用 读取该子 shell 输出getline

关于What would be the benefit of using kmd |& getline outp, and should I use the latter instead?- 不仅没有任何好处,而且这只是语法的一半,你需要类似的东西(加上错误处理):

print knum |& kcmd
kcmd |& getline outp
close(kcmd)

但这只有在包含一个连续读取 stdin 并生成 std​​out 的命令时才开始有意义kcmd,即使它确实如此,也不会对您尝试做的事情产生任何好处,并且会使您的代码不必要地特定于 gawk。

下面是一个示例,说明协进程何时有用,通过管道对传入的数字流进行排序sort,然后在打印这些数字之前对这些数字执行某些操作(例如,将它们除以读取的行数或其他任何内容):

$ cat tst.awk
BEGIN {
    cmd = "sort -rn"
}
{ print |& cmd }
END {
    close(cmd, "to")
    while ( (cmd |& getline line) > 0 ) {
        print line, line / NR
    }
    close(cmd)
}

$ seq 5 | awk -f tst.awk
5 1
4 0.8
3 0.6
2 0.4
1 0.2

基本上,如果您发现自己编写了一个 awk 脚本,需要写入临时文件,请对该文件调用一些外部命令,然后将该命令的输出读回到您的脚本中 - 这就是您应该考虑使用协进程的时候相反,因为它可以消除创建临时文件的需要。

请获取 Arnold Robbins 所著的《Effective AWK 编程》第 5 版一书,并阅读与另一个进程的双向通信相关的部分以获取更多信息。

答案2

不,您应该继续使用简单的“|”。如果您的任务是:向外部工具提供一些数据并使用该工具提供的结果。那么一个简单的单向管道就足够了。

仅在以下情况下才需要双向管道:

  • 您希望在自己的进程的整个生命周期中将外部工具的相同实例保留在内存中。
  • 您发送到外部工具的数据在逻辑上被分成数据包
  • 在发送下一个数据包之前,您需要接收处理一个数据包的结果
  • 您需要根据前一个数据包的结果调整下一个数据包

如果这四个问题之一是“否” - 您不需要双向管道。

很难发明一个现实生活中的例子来说明双向管道的用途。它可能是为了与某些数据库查询工具或网络应用程序一起使用而发明的。但在绝大多数情况下,如果需要使用某种服务器,这些任务通常可以用诸如 、甚至 shell 之类的语言来perl解决pythonawk通常仅保留用于文本处理。

这是一个不现实但技术上正确的示例:

#!/bin/gawk
BEGIN {
  tool="bc"

  print "2+3" |& tool
  tool |& getline res

  if (res>4)
     print "5+6" |& tool
  else 
     print "10+45" |& tool
  tool |& getline res

  close(tool, "to")

  print res
}

正如您在这里所看到的,第一个打印将“查询”发送到外部工具(bc在这种情况下是简单的计算器)。然后根据第一个查询的结果,它发送另一个查询,最后打印结果。它是处理两个查询的工具的同一实例。它从一开始就公开print "2+3" |& command到特别声明close(command, "to")

相关内容