Here, in
A | B /dev/stdin
since B's stdin is a pipe¹, /dev/stdin
will behave like a named pipe.
So it will only work properly if B
opens the file once and reads its contents sequentially from the start, not if:
- it's checking its type beforehand to verify it's a regular file (here the file will appear as a named pipe on Linux and a character device on most other systems).
- it's checking its size beforehand
- it opens it several times
- it needs to seek (change cursor position) within the file (rewind, move to the end...)
- it needs to
mmap()
it, or any other operation that is valid on a regular file but not on a pipe.
And of course B
must not also read from its stdin. Using a different file descriptor, for instance using process substitution (B <(A)
in ksh/zsh/bash) would avoid that problem. That also means B
must not arbitrarily close all its file descriptors (like some commands such as sudo
do for fds above 2).
While most commands will just read files sequentially from start to end, several of those that only take input from filename arguments and not from stdin do that because actually they can't for any ones of the reasons listed above, so your mileage may vary.
$ 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 files are a kind of file that can't be processed sequentially one needs to read an index at the end of the file first before accessing the actual data within the file.
¹ As a corner case, note that the ksh93 shell on Linux uses socketpairs instead of pipes (as pipes there are not peekable). And since on Linux, /dev/stdin
is not a special character device like on other systems, but a "magic" symlink to the actual file, opening /dev/stdin
in that case will never work as it's not possible to open a socket.
$ ksh93 -c 'echo test | cat /dev/stdin'
cat: /dev/stdin: No such device or address
With ksh93, you'll want to use process substitution which uses pipes regardless of the system.
$ ksh93 -c 'cat <(echo test)'
test
fstat()
and abend if it finds anything other than a regular file. – JdeBP Jul 27 '17 at 21:20