While poking around /proc/self
folder for my mksh
shell, I found a peculiar thing: in /proc/self/fd/*
there are all the standard file descriptors (0 for stdin, 1 for stdout, and 2 stderr) some file descriptors, but also some extra ones - 24, 25, 3. And I technically can list them with a glob in the shell:
$ for fd in /proc/self/fd/* ; do echo $fd ; done
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/24
/proc/self/fd/25
/proc/self/fd/3
But when I try to stat
them or use find
on them, they are reported as non-existent.
$ find /proc/self/fd/*
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
find: ‘/proc/self/fd/24’: No such file or directory
find: ‘/proc/self/fd/25’: No such file or directory
/proc/self/fd/3
Same occurs in bash
, but just with just one auxiliary file descriptor.
$ for fd in /proc/self/fd/* ; do echo $fd; done
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/255
/proc/self/fd/3
$ find /proc/self/fd/*
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
find: ‘/proc/self/fd/255’: No such file or directory
/proc/self/fd/3
Question is: what are those additional file descriptors? What is their purpose?
Probing
/proc/self
is a tricky business, since it changes for each process. When you do/proc/self/fd/*
, the shell expands the wildcard, so it's listing its own file descriptors. But when these are passed to another command, likefind
orls
, the paths will now be for that process'/proc/self
, and it may or may not have fds with those numbers.Even trickier, the shell may open file descriptors during wildcard expansion.
Comparing with
/proc/$$/fd
might be illuminating:bash
:By sending it to the background, I got bash to print the PID, and you can see that
/proc/self/fd/3
points tols
' own/proc/<PID>/fd
, which it had opened to scan. The entries with4932
, OTOH, are for bash's fds, and the special one is 255. An explanation is found in this SO post:With
mksh
:Practically the same thing, except that the extra fd is 10, and I'd wager it's for the same reason as bash, since the source code indicates that fd 10 and onwards is used by the shell.
I didn't get two or three extra fds, but it could be due to any number of things happening during wildcard expansion, or due to background jobs or some other obscure reason.
If I run your
for
loop, I do get an ephemeral fd 3:And here, using
strace
to trace the execution:We'll see that the third fd is, in fact,
/proc/<PID>/fd
:Now the question is, why didn't this fd show up in the earlier
ls
tests? It looks like backgrounding had something to do with this:The foreground
ls
shows the missing fd.Now, again tracing with
strace
:We see:
Note the change in PIDs. It seems that wildcard expansion takes place after forking, but variable expansion happens before that. So, fd 3 exists, but in a different process. Now i you use
self
instead of$$
, you'll see both 3 and 255:Addendum
A related answer on Unix&Linux Stackexchange site cites a response from a mail list: