I don't understand the following:
$ cat <(sleep 60) & jobs -l
[1] 63813
[1]+ 63813 Running cat <(sleep 60) &
/proc/63799/fd$ ps --forest
PID TTY TIME CMD
63055 pts/2 00:00:00 bash
63813 pts/2 00:00:00 \_ cat
63814 pts/2 00:00:00 | \_ bash
63815 pts/2 00:00:00 | \_ sleep
63816 pts/2 00:00:00 \_ ps
/proc/63799/fd$ cd /proc/63813/fd
/proc/63813/fd$ ll
total 0
dr-x------ 2 me me 0 Aug 17 16:14 ./
dr-xr-xr-x 9 me me 0 Aug 17 16:14 ../
lrwx------ 1 me me 64 Aug 17 16:14 0 -> /dev/pts/2
lrwx------ 1 me me 64 Aug 17 16:14 1 -> /dev/pts/2
lrwx------ 1 me me 64 Aug 17 16:14 2 -> /dev/pts/2
lr-x------ 1 me me 64 Aug 17 16:14 3 -> 'pipe:[834851]'
lr-x------ 1 me me 64 Aug 17 16:14 63 -> 'pipe:[834851]'
/proc/63813/fd$ cd /proc/63814/fd
/proc/63814/fd$ ll
total 0
dr-x------ 2 me me 0 Aug 17 16:14 ./
dr-xr-xr-x 9 me me 0 Aug 17 16:14 ../
lrwx------ 1 me me 64 Aug 17 16:14 0 -> /dev/pts/2
l-wx------ 1 me me 64 Aug 17 16:14 1 -> 'pipe:[834851]'
lrwx------ 1 me me 64 Aug 17 16:14 2 -> /dev/pts/2
lrwx------ 1 me me 64 Aug 17 16:14 255 -> /dev/pts/2
/proc/63814/fd$ cd /proc/63815/fd
/proc/63815/fd$ ll
total 0
dr-x------ 2 me me 0 Aug 17 16:14 ./
dr-xr-xr-x 9 me me 0 Aug 17 16:14 ../
lrwx------ 1 me me 64 Aug 17 16:14 0 -> /dev/pts/2
l-wx------ 1 me me 64 Aug 17 16:14 1 -> 'pipe:[834851]'
lrwx------ 1 me me 64 Aug 17 16:14 2 -> /dev/pts/2
So I understand that process substitution <(sleep 60) involves the creation of a pipe ('pipe:[834851]') and that the stdout (file descriptor 1) of sleep 60 is linked to that pipe (1 -> 'pipe:[832422]') in writing mode (l-wx------).
But I do not understand the other file descriptors from the other two processes involved here: the cat child process (63813) and the bash child-child process (63814):
- Why has the
catprocess two file descriptors (3 and 63) linked to that same pipe open in reading mode (3 -> 'pipe:[832422]'and63 -> 'pipe:[832422]')? What does each correspond to? - Why has the
bashchild-child process its stdout linked to that same pipe open in writing mode?
Additional comment: For the two file descriptors of cat, at first I thought there was one for each of the child processes (bash and sleep), but replacing sleep by the read builtin, which doesn't spawn an additional child process, gives the same pattern:
$ cat <(read) & jobs -l
[1] 63905
[1]+ 63905 Running cat <(read) &
~$ ps --forest
PID TTY TIME CMD
63055 pts/2 00:00:00 bash
63905 pts/2 00:00:00 \_ cat
63906 pts/2 00:00:00 | \_ bash
63908 pts/2 00:00:00 \_ ps
[1]+ Stopped cat <(read)
~$ ps -o pid,stat,comm
PID STAT COMMAND
63055 Ss bash
63905 T cat
63906 T bash
63909 R+ ps
~$ cd /proc/63905/fd
/proc/63905/fd$ ll
total 0
dr-x------ 2 me me 0 Aug 17 16:31 ./
dr-xr-xr-x 9 me me 0 Aug 17 16:31 ../
lrwx------ 1 me me 64 Aug 17 16:32 0 -> /dev/pts/2
lrwx------ 1 me me 64 Aug 17 16:32 1 -> /dev/pts/2
lrwx------ 1 me me 64 Aug 17 16:32 2 -> /dev/pts/2
lr-x------ 1 me me 64 Aug 17 16:32 3 -> 'pipe:[836281]'
lr-x------ 1 me me 64 Aug 17 16:31 63 -> 'pipe:[836281]'
/proc/63905/fd$ cd /proc/63906/fd
/proc/63906/fd$ ll
total 0
dr-x------ 2 me me 0 Aug 17 16:32 ./
dr-xr-xr-x 9 me me 0 Aug 17 16:32 ../
lrwx------ 1 me me 64 Aug 17 16:32 0 -> /dev/pts/2
l-wx------ 1 me me 64 Aug 17 16:32 1 -> 'pipe:[836281]'
lrwx------ 1 me me 64 Aug 17 16:32 2 -> /dev/pts/2
lrwx------ 1 me me 64 Aug 17 16:32 255 -> /dev/pts/2
Edit
After more tests, it seems the pattern of obtaining file descriptor 3 on top of file descriptor 63 is not systematic with cat <(read) & jobs -l. Maybe some race condition... However, it seems systematic with cat <(sleep 60) & jobs -l.
bash,<( somecomand )redirects the output to a file descriptor, so it can be used in place of a file.sleepdoes not produce any output.sleepdoesn't produce any output, I only used it to have some time to have a look at the file descriptors associated to the different processes. I then realized I could usereadinstead in order to "block" the execution of the command in the background while looking into the/proc/<PID>directories.sleepstill inherits an stdout file descriptor from its parent, and the fact that it doesn't print anything isn't really relevant to how the plumbing is set up. (Consider that the program inside could be something likefind, which may or may not print something.)