管道是如何工作的?如果我通过命令行界面运行程序并将输出重定向到文件,那么在该文件被写入时,我是否能够将该文件作为输入流传递给另一个程序?
基本上,当一行内容被写入文件时,我希望它能立即被传递到第二个应用程序中(我正在尝试从现有程序动态绘制图形)。只是不确定管道是否会在移动到下一个命令之前完成第一个命令。
任何反馈都将不胜感激!
管道是如何工作的?如果我通过命令行界面运行程序并将输出重定向到文件,那么在该文件被写入时,我是否能够将该文件作为输入流传递给另一个程序?
基本上,当一行内容被写入文件时,我希望它能立即被传递到第二个应用程序中(我正在尝试从现有程序动态绘制图形)。只是不确定管道是否会在移动到下一个命令之前完成第一个命令。
任何反馈都将不胜感激!
如果你想将一个程序的输出重定向为另一个程序的输入,只需要使用简单的管道:
program1 arg arg | program2 arg arg
如果你想将program1
的输出保存到一个文件中,同时又要将它传递给program2
,你可以使用tee(1)
命令:
program1 arg arg | tee output-file | program2 arg arg
管道中的所有程序同时运行。大多数程序通常使用阻塞I/O:如果它们在尝试读取输入时没有任何内容可用,它们会阻塞:也就是说,它们停止运行,并且操作系统将其取消调度以等待更多输入(以避免占用CPU)。同样地,如果管道中较早的程序写入数据的速度比后续程序读取数据的速度快,最终管道的缓冲区将填满并导致写入程序阻塞:操作系统将其取消调度直到读取程序清空了管道的缓冲区,然后它可以继续写入。
编辑
如果您想使用program1
的输出作为命令行参数,您可以使用反引号或$()
语法:
# Runs "program1 arg", and uses the output as the command-line arguments for
# program2
program2 `program1 arg`
# Same as above
program2 $(program1 arg)
应该优先使用$()
语法,因为它们更清晰,并且可以嵌套。
管道在运行第二个命令之前不会完成第一个命令。Unix(和Linux)中的管道同时运行所有命令。如果一个命令:
需要输入但是没有得到。
已经产生的输出比其后继者准备消耗的要多。
对于大多数程序,输出是缓冲的,这意味着操作系统在将输出传递给管道的下一个阶段之前累积了大量输出(可能是大约8000个字符)。这种缓冲是为了避免进程和内核之间过多的切换。
如果您希望管道上的输出能够立即发送,您可以使用非缓冲的I/O,这在C语言中意味着调用类似于fflush()
这样的东西来确保任何缓冲输出都立即被发送到下一个进程中。非缓冲输入也是可能的,但通常是不必要的,因为饥饿等待输入的进程通常不会等待完整的缓冲区,而是会处理您可以获得的任何输入。
对于典型的应用程序,不建议使用非缓冲输出;通常情况下默认设置可以获得最佳性能。但是,在您需要在第一个进程有信息可用时立即进行动态图形处理的情况下,您绝对需要使用非缓冲输出。如果您正在使用C语言,只需在需要发送输出时调用fflush(stdout)
即可。
stdin
和 stdout
进行通信,请确保在写入后调用 fflush(stdout)
或找到某种方式禁用标准IO缓冲。我能想到最好的参考资料是 UNIX环境高级编程 或 UNIX网络编程:卷2。您也可以从这篇文章开始学习。如果您的两个程序坚持要读写文件而不使用stdin/stdout,您可能会发现可以使用命名管道代替文件。
使用mknod(1)命令创建一个命名管道:
$ mknod /tmp/named-pipe p
然后配置你的程序以读写/tmp/named-pipe(使用你认为合适的任何路径/名称)。
在这种情况下,两个程序将并行运行,在管道变满/空时按需要阻塞,如其他答案所述。