Sondar /proc/self
é um negócio complicado, pois muda para cada processo. Quando você executa /proc/self/fd/*
, o shell expande o caractere curinga, listando seus próprios descritores de arquivo. Mas quando estes são passados para outro comando, como find
ou ls
, os caminhos agora serão para esse processo ' /proc/self
, e pode ou não ter fds com esses números.
Ainda mais complicado, o shell pode abrir descritores de arquivos durante a expansão do caractere curinga.
A comparação com /proc/$$/fd
pode ser esclarecedora:
bash
:
$ ls -l /proc/self/fd /proc/$$/fd/* &
[1] 5172
$ lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/255 -> /dev/pts/1
/proc/self/fd:
total 0
lrwx------ 1 muru muru 64 Jan 1 20:24 0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:24 1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:24 2 -> /dev/pts/1
lr-x------ 1 muru muru 64 Jan 1 20:24 3 -> /proc/5172/fd
[1]+ Done ls --color=auto -l /proc/self/fd /proc/$$/fd/*
Ao enviá-lo para o segundo plano, recebi o bash para imprimir o PID, e você pode ver que /proc/self/fd/3
aponta para ls
'own /proc/<PID>/fd
, que ele abriu para digitalizar. As entradas com 4932
, OTOH, são para fds do bash, e a especial é 255. Uma explicação é encontrada em este post do SO :
Os arquivos abertos são 0 (stdin), 1 (stdout) e 2 (stderr). 255 é um pequeno truque que bash usa para manter uma cópia destes para quando eles estão redirecionado. Isso é específico para o bash.
Fonte: link
com mksh
:
$ ls -l /proc/self/fd /proc/$$/fd/* &
[1] 5075
$ lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/10 -> /dev/tty
lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/2 -> /dev/pts/1
/proc/self/fd:
total 0
lrwx------ 1 muru muru 64 Jan 1 20:22 0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 2 -> /dev/pts/1
lr-x------ 1 muru muru 64 Jan 1 20:22 3 -> /proc/5075/fd
[1] + Done ls -l /proc/self/fd /proc/$$/fd/*
Praticamente a mesma coisa, exceto que o extra fd é 10, e eu aposto que é pelo mesmo motivo que o bash, já que o código-fonte indica que o fd 10 e em diante é usado pelo shell.
Eu não consegui dois ou três fds extras, mas isso pode ser devido a qualquer número de coisas que acontecem durante a expansão de curingas, ou devido a trabalhos em segundo plano ou algum outro motivo obscuro.
Se eu executar o seu loop for
, recebo um efêmero fd 3:
$ for fd in /proc/$$/fd/* ; do ls -l $fd ; done
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/255 -> /dev/pts/1
ls: cannot access '/proc/6012/fd/3': No such file or directory
E aqui, usando strace
para rastrear a execução:
strace -e open -o log bash -c 'for fd in /proc/$$/fd/* ; do : ; done'
Veremos que o terceiro fd é, na verdade, /proc/<PID>/fd
:
$ tail log
open("/usr/lib/libreadline.so.7", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libncursesw.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/dev/tty", O_RDWR|O_NONBLOCK) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 3
open("/proc/9975/fd/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
+++ exited with 0 +++
Agora a questão é: por que esse fd não apareceu nos testes anteriores de ls
? Parece que o backgrounding tem algo a ver com isso:
$ ls -l /proc/$$/fd/* &
[1] 10091
$ lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/255 -> /dev/pts/1
[1]+ Done ls --color=auto -l /proc/self/fd /proc/$$/fd/*
$ ls -l /proc/$$/fd/*
ls: cannot access '/proc/10076/fd/3': No such file or directory
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/255 -> /dev/pts/1
O primeiro plano ls
mostra a falta de fd.
Agora, novamente rastreando com strace
:
strace -fe open,execve,fork -o log bash -ic 'ls -l /proc/self/fd /proc/$$/fd/* &'
Nós vemos:
10731 execve("/usr/bin/bash", ["bash", "-ic", "ls -l /proc/$$/fd/* &"], [/* 67 vars */]) = 0
10731 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
# snip
10734 open("/proc/10731/fd/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
10734 execve("/usr/bin/ls", ["ls", "--color=auto", "-l", "/proc/10731/fd/0", "/proc/10731/fd/1", "/proc/10731/fd/2", "/proc/10731/fd/255"], [/* 68 vars */]) = 0
Observe a mudança nos PIDs. Parece que a expansão de curingas ocorre após a bifurcação, mas a expansão de variáveis acontece antes disso. Então, o fd 3 existe, mas em um processo diferente. Agora que você usa self
em vez de $$
, você verá os dois e os 255:
$ strace -fe open,execve -o log bash -ic 'ls -l /proc/self/fd/* &'
[1] 10790
ls: cannot access '/proc/self/fd/255': No such file or directory
ls: cannot access '/proc/self/fd/3': No such file or directory
lrwx------ 1 muru muru 64 Jan 2 18:04 /proc/self/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 18:04 /proc/self/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 18:04 /proc/self/fd/2 -> /dev/pts/1