Why does `cat <(cat)` produce EIO?

1. Explain why cat <(cat) produces EIO

( 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:

$ echo $$
906
$ tty
/dev/pts/14
$ cat <(sleep 12345)

Go to another pty #2:

$ ps t pts/14 j
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
   903    906    906    906 pts/14    29999 Ss       0   0:00 bash
   906  29998    906    906 pts/14    29999 S        0   0:00 bash
 29998  30000    906    906 pts/14    29999 S        0   0:00 sleep 12345
   906  29999  29999    906 pts/14    29999 S+       0   0:00 cat /dev/fd/63
$ ps p 903 j
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
     1    903    903    903 ?            -1 Ss       0   0:07 SCREEN -T linux -U
$

Let me explain it (according to the APUE book, 2nd edition):

  1. The TPGID being 29999 indicates that cat (PID 29999) is the foreground process group which is now controlling the terminal (pts/14). And sleep is in the background process group (PGID 906).
  2. The process group of 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 PID 906's PPID is 903 and 903 is in a different session.)
  3. When the process in an orphaned background process group reads from its controlling terminal, read() would fail with EIO.

2. Explain why cat <(cat) sometimes works (not really!)

Daniel Voina mentioned in a comment that cat <(cat) works on OS X with Bash 3.2.57. I just managed to reproduce it also on Linux with Bash 4.4.12.

From pty #1:

bash-4.4# echo $$
10732
bash-4.4# tty
/dev/pts/0
bash-4.4# cat <(cat)
cat: -: Input/output error
bash-4.4#
bash-4.4#
bash-4.4# bash --norc --noprofile  # start a new bash
bash-4.4# tac <(cat)
                      <-- It's waiting here so looks like it's working.

(The first cat <(cat) failing with EIO was explained in the first part of my answer.)

Go to another pty #2:

bash-4.4# ps t pts/0 j
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
10527 10732 10732 10732 pts/0    10805 Ss       0   0:00 bash
10732 10803 10803 10732 pts/0    10805 S        0   0:00 bash --norc --noprofile
10803 10804 10803 10732 pts/0    10805 S        0   0:00 bash --norc --noprofile
10804 10806 10803 10732 pts/0    10805 T        0   0:00 cat
10803 10805 10805 10732 pts/0    10805 S+       0   0:00 tac /dev/fd/63
bash-4.4# ps p 10527 j
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
10526 10527 10527 10527 ?           -1 Ss       0   0:00 SCREEN -T dtterm -U
bash-4.4#

Let's see what's happening:

  1. The TPGID being 10805 indicates that tac (PID 10805) is the foreground process group which is now controlling the terminal (pts/0). And cat (PID 10806) is in the background process group (PGID 10803).

  2. But this time the pgrp 10803 is not orphanded because its member PID 10803 (bash)'s parent (PID 10732, bash) is in another pgrp (PGID 10732) and it's in the same session (SID 10732).

  3. 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 when cat reads stdin, SIGTTIN will be sent to it and by default this signal would stop the process. That's why the cat's STAT column was shown as T (stopped) in the ps 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 PID 906 is the session leader, but the bash of PID 10803 in the 2nd part is not the session leader.)


The accepted answer explained why, but I saw one solution which can solve it. It is by subshelling it with additional (), such as:

(cat <(cat))

Please find the solution details here: https://unix.stackexchange.com/a/244333/89706