I have a program that reads from two input files simultaneously. I'd like to have this program read from standard input. I thought I'd use something like this:
$program1 <(cat) <($program2)
but I've just discovered that
cat <(cat)
produces
....
mmap2(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb758e000
read(0, 0xb758f000, 131072) = -1 EIO (Input/output error)
....
cat: -: Input/output error
and similarly,
$ cat <(read -n 1)
bash: read: read error: 0: Input/output error
So... Linux is failing to read
at the syscall level. That's interesting. Is bash
not wiring stdin to the subshell? :(
Is there a solution to this? I specifically need to use process substitution (the ... <(...)
format) because $program1
(tail
, incidentally) expects files, and I need to do some preprocessing (with od
) on standard input before I can pass it to tail
- I can't just specify /dev/stdin
et al.
EDIT:
What I actually want to do is read from a file (which another process will be writing to) while I also read from standard input so I can accept commands and such. I was hoping I could do
tail -f <(od -An -vtd1 -w1) <(cat fifo)
to read from standard input and the FIFO simultaneously and drop that into a single stdout stream I could run through awk (or similar). I know I could solve this trivially in any scripting language, but I like learning how to make bash
do everything :P
EDIT 2: I've asked a new question that more fully explains the context I described just above.
1. Explain why
cat <(cat)
producesEIO
( I'm using Debian Linux 8.7, Bash 4.4.12 )
Let's replace
<(cat)
with the long running<(sleep)
to see what's happening.From pty #1:
Go to another pty #2:
Let me explain it (according to the APUE book, 2nd edition):
TPGID
being29999
indicates thatcat
(PID29999
) is the foreground process group which is now controlling the terminal (pts/14
). Andsleep
is in the background process group (PGID906
).906
is now an orphaned process group because "the parent of every member is either itself a member of the group or is not a member of the group’s session". (The PID906
's PPID is903
and903
is in a different session.)read()
would fail withEIO
.2. Explain why
cat <(cat)
sometimes works (not really!)Daniel Voina mentioned in a comment that
cat <(cat)
works on OS X with Bash3.2.57
. I just managed to reproduce it also on Linux with Bash4.4.12
.From pty #1:
(The first
cat <(cat)
failing withEIO
was explained in the first part of my answer.)Go to another pty #2:
Let's see what's happening:
The
TPGID
being10805
indicates thattac
(PID10805
) is the foreground process group which is now controlling the terminal (pts/0
). Andcat
(PID10806
) is in the background process group (PGID10803
).But this time the pgrp
10803
is not orphanded because its member PID10803
(bash
)'s parent (PID10732
,bash
) is in another pgrp (PGID10732
) and it's in the same session (SID10732
).According to the APUE book,
SIGTTIN
will be "generated by the terminal driver when a process in a (non-orphaned) background process group tries to read from its controlling terminal". So whencat
reads stdin,SIGTTIN
will be sent to it and by default this signal would stop the process. That's why thecat
'sSTAT
column was shown asT
(stopped) in theps
output. Since it's stopped the data we input from keyboard are not sent to it at all. So it just looks like it's working but it's not really.Conclusion:
So the different behaviors (
EIO
vs.SIGTTIN
) depend on whether the current Bash is a session leader or not. (In the 1st part of my answer, the bash of PID906
is the session leader, but the bash of PID10803
in the 2nd part is not the session leader.)