如何在 shell 管道中使用不同的文件描述符?
Posted
技术标签:
【中文标题】如何在 shell 管道中使用不同的文件描述符?【英文标题】:How to use a different file-descriptor in a shell pipeline? 【发布时间】:2021-02-06 18:23:08 【问题描述】:我正在处理一个脚本,它首先调用嘈杂的(stdout
和 stderr
上的大量诊断)程序,然后使用其他工具处理其输出。
程序的冗长使得它不可能简单地将其标准输出发送到管道,所以目前我们使用一个临时文件——我想结束这种做法。
我们可以要求程序将数据写入/dev/fd/N
,而不是/tmp/foo
——它会,没问题(例如,它不需要seek
文件)。
它目前发送给stdout
和stderr
的噪音,可以继续往那里去——操作员见惯了,如果它消失了会报警……
但是如何安排描述符N
存在并发送到下一个程序的stdin
?
noisy -o /dev/fd/N ?????| filter -i /dev/stdin
如果这需要bash
,那就这样吧,但我当然更喜欢适合整个 sh 家族的解决方案。
【问题讨论】:
我认为你应该继续使用临时文件。 临时文件坏了。它们的效率较低,并且会乱扔文件系统——可靠地清理它们所需的代码比我的问题的任何答案都要丑陋。它们可能会被某人匆忙使用——太忙而不能正确做事。但是像你一样鼓励使用它们比使用它们更错误。 好吧,那么祝你好运 你能使用命名管道吗,如Example of using named pipes in Linux Bash? 一个更有成效的方法可能是编写一个包装器来抑制噪音并只保留有用的输出。如果噪音是可预测的,它可以像单个grep
一样简单。
【参考方案1】:
如果我正确理解了您的问题,那么您有一个程序可以将噪声写入标准输出和标准错误,并将有用的数据写入使用-o
选项指定的文件。您希望标准输出和标准错误保持原样,但将有用的数据通过管道传输到过滤程序而不是将其写入文件。
使用 Bash 最简单的方法是使用进程替换(请参阅 ProcessSubstitution - Greg's Wiki):
noisy -o >(filter -i /dev/stdin)
请注意,进程替换在某些 sh 系列 shell 中不可用,它在某些(不常见的)平台上不适用于 Bash,并且无法获取使用 Bash 之前的进程替换创建的进程的退出状态4.4 版。
另一种可能的方式来做(我认为)你想要的是:
exec 3>&1
exec 4>&1; noisy -o /dev/fd/4 >&3 ; | filter -i /dev/stdin
exec 3>&1
使文件描述符 3 引用“真实”标准输出。
exec 4>&1
(因为它是在作为管道第一阶段的进程中运行的)使文件描述符 4 引用管道中下一阶段的输入。
noisy ... >&3
强制 noisy
的标准输出转到“真正的”标准输出。
写入/dev/fd/4
(至少在 Linux 上)写入管道中的下一个阶段。
我只用 Bash 测试过它,但我认为它应该适用于其他 sh 系列 shell。
【讨论】:
感谢您的解决方案!老实说,我不明白如何让我的问题更清楚——但我很高兴,你明白了 :)以上是关于如何在 shell 管道中使用不同的文件描述符?的主要内容,如果未能解决你的问题,请参考以下文章
五周第四次课 8.6 管道符和作业控制 8.7/8.8 shell变量 8.9 环境变量配置文件