Eu estava pesquisando a outra pergunta , quando percebi que não entendia o que estava acontecendo, quais são esses /dev/fd/*
arquivos e como os processos filhos podem abri-los.
bash
process-substitution
x-yuri
fonte
fonte
Respostas:
Bem, há muitos aspectos nisso.
Descritores de arquivo
Para cada processo, o kernel mantém uma tabela de arquivos abertos (bem, pode ser implementada de forma diferente, mas como você não pode vê-lo de qualquer maneira, basta assumir que é uma tabela simples). Essa tabela contém informações sobre qual arquivo está / onde pode ser encontrado, em qual modo você o abriu, em qual posição está lendo / gravando e o que mais é necessário para realizar operações de E / S nesse arquivo. Agora, o processo nunca chega a ler (ou mesmo escrever) essa tabela. Quando o processo abre um arquivo, ele recebe de volta o chamado descritor de arquivo. O que é simplesmente um índice na tabela.
O diretório
/dev/fd
e seu conteúdoNo Linux,
dev/fd
na verdade, é um link simbólico para/proc/self/fd
./proc
é um pseudo sistema de arquivos no qual o kernel mapeia várias estruturas de dados internas para serem acessadas com a API do arquivo (para que pareçam arquivos / diretórios / links simbólicos regulares para os programas). Especialmente, há informações sobre todos os processos (que deram o nome). O link simbólico/proc/self
sempre se refere ao diretório associado ao processo atualmente em execução (ou seja, o processo que o solicita; portanto, processos diferentes verão valores diferentes). No diretório do processo, há um subdiretóriofd
que para cada arquivo aberto contém um link simbólico cujo nome é apenas a representação decimal do descritor de arquivo (o índice na tabela de arquivos do processo, consulte a seção anterior) e cujo destino é o arquivo ao qual ele corresponde.Descritores de arquivo ao criar processos filhos
Um processo filho é criado por a
fork
. Afork
faz uma cópia dos descritores de arquivo, o que significa que o processo filho criado possui a mesma lista de arquivos abertos que o processo pai. Portanto, a menos que um dos arquivos abertos seja fechado pelo filho, o acesso a um descritor de arquivo herdado no filho acessará o mesmo arquivo que o descritor de arquivo original no processo pai.Observe que, após uma bifurcação, você inicialmente possui duas cópias do mesmo processo, que diferem apenas no valor de retorno da chamada da bifurcação (o pai obtém o PID do filho e o filho recebe 0). Normalmente, um fork é seguido por um
exec
para substituir uma das cópias por outro executável. Os descritores de arquivo aberto sobrevivem a esse executivo. Observe também que, antes do exec, o processo pode fazer outras manipulações (como fechar arquivos que o novo processo não deve obter ou abrir outros arquivos).Tubos sem nome
Um canal sem nome é apenas um par de descritores de arquivos criados a pedido do kernel, para que tudo o que foi escrito no primeiro descritor de arquivo seja passado para o segundo. O uso mais comum é para a construção
foo | bar
de tubulação debash
, onde a saída padrão defoo
é substituída pela parte de gravação do tubo e a entrada padrão é substituída pela parte de leitura. A entrada padrão e a saída padrão são apenas as duas primeiras entradas na tabela de arquivos (as entradas 0 e 1; 2 são erro padrão) e, portanto, substituí-las significa reescrever essa entrada da tabela com os dados correspondentes ao outro descritor de arquivo (novamente, o implementação real pode ser diferente). Como o processo não pode acessar a tabela diretamente, há uma função do kernel para fazer isso.Substituição de processo
Agora, temos tudo junto para entender como a substituição do processo funciona:
echo
processo. O processo filho (que é uma cópia exata dobash
processo original ) fecha a extremidade de leitura do tubo e substitui sua própria saída padrão pela extremidade de gravação do tubo. Dado queecho
é um shell embutido,bash
pode poupar aexec
chamada, mas isso não importa de qualquer maneira (o shell embutido também pode ser desativado; nesse caso, é executado/bin/echo
).<(echo 1)
pelo link do pseudo arquivo ao/dev/fd
se referir ao final da leitura do canal não nomeado./dev/fd/
. Como o descritor de arquivo correspondente ainda está aberto, ele ainda corresponde à extremidade de leitura do canal. Portanto, se o programa PHP abre o arquivo fornecido para leitura, o que ele realmente faz é criar umsecond
descritor de arquivo para o final da leitura do canal não nomeado. Mas isso não é problema, poderia ler também.echo
comando que vai para o final de gravação do mesmo canal.fonte
php
cenário, masphp
não lida bem com canos . Além disso, considerando o comandocat <(echo test)
, o estranho aqui é quebash
garfos uma vezcat
, mas duas vezesecho test
.Tomando emprestado da
celtschk
resposta,/dev/fd
é um link simbólico para/proc/self/fd
. E/proc
é um pseudo sistema de arquivos, que apresenta informações sobre processos e outras informações do sistema em uma estrutura hierárquica semelhante a arquivo. Os arquivos/dev/fd
correspondem aos arquivos, abertos por um processo e têm o descritor de arquivos como seus nomes e os próprios arquivos como seus destinos. Abrir o arquivo/dev/fd/N
é equivalente a duplicar o descritorN
(assumindo que o descritorN
esteja aberto).E aqui estão os resultados da minha investigação de como funciona (a
strace
saída é livre de detalhes desnecessários e modificada para expressar melhor o que está acontecendo):Basicamente,
bash
cria um canal e passa suas extremidades para seus filhos como descritores de arquivo (leia final para1.out
e escreva fim2.out
). E passa read end como um parâmetro de linha de comando para1.out
(/dev/fd/63
). Por aqui1.out
é possível abrir/dev/fd/63
.fonte