我想将程序 A 的输出通过管道传输到程序 B 中。程序 B 不支持从 stdin 读取,仅支持从文件读取。我可以简单地做A | B /dev/stdin ?
事实上,它似乎有效,但我想确保在运行管道时,B 从 /dev/stdin 获取的唯一内容是 A 编写的内容。
答案1
在此处
A | B /dev/stdin
由于 B 的 stdin 是一个管道,/dev/stdin
因此其行为类似于命名管道。
B
因此,只有打开文件一次并从头开始按顺序读取其内容时,它才能正常工作,而不是:
- 它会事先检查其类型以验证它是常规文件(此处该文件将在 Linux 上显示为命名管道,并且在 Linux 上显示为命名管道)字符设备在大多数其他系统上)。
- 它事先检查它的大小
- 它会打开它几次
- 它需要在文件中查找(更改光标位置)(倒带、移动到末尾...)
- 它需要
mmap()
它,或者对常规文件有效但对管道无效的任何其他操作。
而且当然B
也不能从其标准输入中读取。使用不同的文件描述符,例如使用流程替代(B <(A)
在 ksh/zsh/bash 中)可以避免这个问题。这也意味着B
不得任意关闭其所有文件描述符(就像某些命令,例如sudo
do for fds 以上 2)。
虽然大多数命令只是从头到尾顺序读取文件,但其中一些命令仅有的从文件名参数获取输入而不是从标准输入执行此操作,因为实际上它们不能出于上面列出的任何原因,因此您的里程可能会有所不同。
$ unzip -l file.zip
Archive: file.zip
Length Date Time Name
--------- ---------- ----- ----
48894 2020-12-05 07:35 file
--------- -------
48894 1 file
$ cat file.zip | unzip -l /dev/stdin
Archive: /dev/stdin
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of /dev/stdin or
/dev/stdin.zip, and cannot find /dev/stdin.ZIP, period.
infozip 文件是一种无法顺序处理的文件,需要先读取文件末尾的索引,然后才能访问文件中的实际数据。
1 作为一个极端情况,请注意 Linux 上的 ksh93 shell 使用套接字对而不是管道(因为管道没有可窥视的)。自从在 Linux 上,/dev/stdin
它不是像其他系统上那样的特殊字符设备,而是一个“魔法”到实际文件的符号链接,/dev/stdin
在这种情况下打开将永远无法工作,因为不可能打开一个插座。
$ ksh93 -c 'echo test | cat /dev/stdin'
cat: /dev/stdin: No such device or address
对于 ksh93,您将需要使用进程替换,无论系统如何,它都使用管道。
$ ksh93 -c 'cat <(echo test)'
test
答案2
(另请参阅 JdeBP 的评论)
是的,但推荐的方法是使用/dev/fd/0
.例如在书中提到《UNIX环境下的高级编程》:
它允许使用路径名参数的程序以与其他路径名相同的方式处理标准输入和标准输出。
/dev/fd/0
和/dev/stdin
是同一设备。请参阅此处以获取大量有用的信息: