如何在 shell 管道中使用不同的文件描述符?

Mik*_* T. 4 unix bash pipeline file-descriptor sh

stdout我正在处理一个脚本,它首先调用一个嘈杂的(对和)程序进行大量诊断stderr,然后使用其他工具处理其输出。

该程序的冗长使得不可能简单地将其标准输出发送到管道,因此目前我们使用临时文件——我想结束这种做法。

我们可以/tmp/foo要求程序将数据写入,而不是写入 - 它会,没有问题(例如,/dev/fd/N它不需要文件)。seek

stdout它当前发送到和的噪音stderr可以继续到那里——操作员已经习惯了看到它,并且如果它消失就会感到震惊......

但是我如何安排描述符N存在并发送到下一个程序中stdin

noisy -o /dev/fd/N ?????| filter -i /dev/stdin
Run Code Online (Sandbox Code Playgroud)

如果这需要bash,那就这样吧,但当然,我更喜欢适合整个 sh 系列的解决方案。

pjh*_*pjh 7

如果我正确理解您的问题,您就有一个程序可以将噪声写入标准输出和标准错误,并将有用的数据写入使用选项指定的文件-o。您希望标准输出和标准错误保持原样,但将有用的数据通过管道传输到过滤器程序中,而不是将其写入文件。

使用 Bash 实现这一点的最简单方法是使用进程替换(请参阅ProcessSubstitution - Greg's Wiki):

noisy -o >(filter -i /dev/stdin)
Run Code Online (Sandbox Code Playgroud)

请注意,进程替换在某些 sh ​​系列 shell 中不可用,在某些(不常见)平台上的 Bash 中不可用,并且在 4.4 版本之前的 Bash 中无法获取通过进程替换创建的进程的退出状态。

另一种可能的方法是:

exec 3>&1
{ exec 4>&1; noisy -o /dev/fd/4 >&3 ; } | filter -i /dev/stdin
Run Code Online (Sandbox Code Playgroud)
  • exec 3>&1使文件描述符 3 引用“真实”标准输出。
  • exec 4>&1(因为它在管道第一阶段的进程中运行)使文件描述符 4 引用管道中下一个阶段的输入。
  • noisy ... >&3强制 的标准输出noisy转到“真实”标准输出。
  • 写入/dev/fd/4(至少在 Linux 上)写入管道中的下一个阶段。

我只用 Bash 测试过它,但我认为它应该可以与其他 sh 系列 shell 一起使用。