Estaba investigando la otra pregunta , cuando me di cuenta de que no entiendo lo que sucede debajo del capó, qué son esos /dev/fd/*
archivos y cómo es que los procesos secundarios pueden abrirlos.
bash
process-substitution
x-yuri
fuente
fuente
Respuestas:
Bueno, hay muchos aspectos.
Descriptores de archivo
Para cada proceso, el kernel mantiene una tabla de archivos abiertos (bueno, podría implementarse de manera diferente, pero como no puede verlo de todos modos, puede asumir que es una tabla simple). Esa tabla contiene información sobre qué archivo es / dónde se puede encontrar, en qué modo lo abrió, en qué posición está leyendo / escribiendo actualmente, y cualquier otra cosa necesaria para realizar operaciones de E / S en ese archivo. Ahora el proceso nunca llega a leer (o incluso escribir) esa tabla. Cuando el proceso abre un archivo, recupera el llamado descriptor de archivo. Que es simplemente un índice en la tabla.
El directorio
/dev/fd
y su contenido.En Linux
dev/fd
es en realidad un enlace simbólico a/proc/self/fd
./proc
es un pseudo sistema de archivos en el que el kernel mapea varias estructuras de datos internas para acceder con la API de archivos (por lo que solo parecen archivos / directorios / enlaces simbólicos normales a los programas). Especialmente hay información sobre todos los procesos (que es lo que le dio el nombre). El enlace simbólico/proc/self
siempre se refiere al directorio asociado con el proceso que se está ejecutando actualmente (es decir, el proceso que lo solicita; por lo tanto, diferentes procesos verán diferentes valores). En el directorio del proceso, hay un subdirectoriofd
que para cada archivo abierto contiene un enlace simbólico cuyo nombre es solo la representación decimal del descriptor de archivo (el índice en la tabla de archivos del proceso, consulte la sección anterior), y cuyo objetivo es el archivo al que corresponde.Descriptores de archivo al crear procesos secundarios
Un proceso hijo es creado por a
fork
. Afork
hace una copia de los descriptores de archivo, lo que significa que el proceso hijo creado tiene la misma lista de archivos abiertos que el proceso padre. Por lo tanto, a menos que el niño cierre uno de los archivos abiertos, el acceso a un descriptor de archivo heredado en el niño accederá al mismo archivo que el acceso al descriptor de archivo original en el proceso padre.Tenga en cuenta que después de una bifurcación, inicialmente tiene dos copias del mismo proceso que difieren solo en el valor de retorno de la llamada de la bifurcación (el padre obtiene el PID del niño, el niño obtiene 0). Normalmente, un tenedor es seguido por un
exec
para reemplazar una de las copias por otro ejecutable. Los descriptores de archivos abiertos sobreviven a ese ejecutivo. Tenga en cuenta también que antes del ejecutivo, el proceso puede hacer otras manipulaciones (como cerrar archivos que el nuevo proceso no debería obtener o abrir otros archivos).Tubos sin nombre
Una tubería sin nombre es solo un par de descriptores de archivo creados a pedido por el núcleo, de modo que todo lo escrito en el primer descriptor de archivo se pasa al segundo. El uso más común es para la construcción
foo | bar
de tuberías debash
, donde la salida estándar defoo
se reemplaza por la parte de escritura de la tubería, y la entrada estándar se reemplaza por la parte de lectura. La entrada estándar y la salida estándar son solo las dos primeras entradas en la tabla de archivos (la entrada 0 y 1; 2 es un error estándar), y por lo tanto reemplazarla significa simplemente reescribir esa entrada de la tabla con los datos correspondientes al otro descriptor de archivo (nuevamente, el La implementación real puede diferir). Como el proceso no puede acceder a la tabla directamente, hay una función del núcleo para hacerlo.Proceso de sustitución
Ahora tenemos todo junto para comprender cómo funciona la sustitución del proceso:
echo
proceso. El proceso secundario (que es una copia exacta delbash
proceso original ) cierra el extremo de lectura de la tubería y reemplaza su propia salida estándar con el final de escritura de la tubería. Dado queecho
es un shell integrado,bash
puede ahorrarse laexec
llamada, pero no importa de todos modos (el shell incorporado también puede estar deshabilitado, en cuyo caso se ejecuta/bin/echo
).<(echo 1)
por el enlace del pseudo archivo al/dev/fd
referirse al final de la lectura de la tubería sin nombre./dev/fd/
. Dado que el descriptor de archivo correspondiente todavía está abierto, todavía corresponde al final de la lectura de la tubería. Por lo tanto, si el programa PHP abre el archivo dado para leer, lo que realmente hace es crear unsecond
descriptor de archivo para el final de la lectura de la tubería sin nombre. Pero eso no es problema, podría leer de cualquiera.echo
comando que va al final de la escritura de la misma tubería.fuente
php
escenario, perophp
no maneja bien las tuberías . Además, considerando el comandocat <(echo test)
, lo extraño aquí es que sebash
bifurca una vezcat
, pero dos vecesecho test
.Tomando prestado de
celtschk
la respuesta de,/dev/fd
es un enlace simbólico a/proc/self/fd
. Y/proc
es un pseudo sistema de archivos, que presenta información sobre procesos y otra información del sistema en una estructura jerárquica similar a un archivo. Los archivos en/dev/fd
corresponden a archivos, abiertos por un proceso y tienen un descriptor de archivo como sus nombres y los archivos mismos como sus objetivos. Abrir el archivo/dev/fd/N
es equivalente a duplicar el descriptorN
(suponiendo que el descriptorN
esté abierto).Y aquí están los resultados de mi investigación de cómo funciona (la
strace
salida se deshace de detalles innecesarios y se modifica para expresar mejor lo que está sucediendo):Básicamente,
bash
crea una tubería y pasa sus extremos a sus elementos secundarios como descriptores de archivo (lectura de fin1.out
y escritura de fin2.out
). Y pasa el fin de lectura como un parámetro de línea de comando a1.out
(/dev/fd/63
). De esta manera1.out
se puede abrir/dev/fd/63
.fuente