¿Por qué la sustitución del proceso da como resultado un archivo llamado / dev / fd / 63 que es una tubería?

40

Estoy tratando de entender las tuberías con nombre en el contexto de este ejemplo en particular.

Escribo <(ls -l)en mi terminal y obtener la salida como, bash: /dev/fd/63: Permission denied.

Si escribo cat <(ls -l), podría ver el contenido del directorio. Si reemplazo el catcon echo, creo que obtengo el nombre del terminal (¿o es así?).

echo <(ls -l)da la salida como /dev/fd/63.

Además, este resultado de ejemplo no está claro para mí.

ls -l <(echo "Whatever")
lr-x------ 1 root root 64 Sep 17 13:18 /dev/fd/63 -> pipe:[48078752]

Sin embargo, si doy, ls -l <()me enumera el contenido del directorio.

¿Qué está sucediendo en el caso de la tubería con nombre?

Ramesh
fuente

Respuestas:

37

Cuando lo hace <(some_command), su shell ejecuta el comando dentro de los paréntesis y reemplaza todo con un descriptor de archivo, que está conectado a la salida estándar del comando. Entonces, /dev/fd/63hay una tubería que contiene la salida de su llamada ls.

Cuando lo hace <(ls -l), obtiene un Permission deniederror, porque toda la línea se reemplaza con la tubería, tratando de llamar efectivamente /dev/fd/63como un comando, que no es ejecutable.

En tu segundo ejemplo, se cat <(ls -l)convierte cat /dev/fd/63. A medida que cat lee los archivos dados como parámetros, obtienes el contenido. echopor otro lado, solo da salida a sus parámetros "tal cual".

El último caso que tiene, <()simplemente se reemplaza por nada, ya que no hay comando. Pero esto no es consistente entre los shells, en zsh todavía obtienes una tubería (aunque vacía).

Resumen : le <(command)permite usar la salida de un comando, donde normalmente necesitaría un archivo.

Editar: como señala Gilles , esta no es una tubería con nombre, sino una tubería anónima. La principal diferencia es que solo existe, mientras el proceso se esté ejecutando, mientras que una tubería con nombre (creada, por ejemplo, con mkfifo) permanecerá sin procesos adjuntos.

crater2150
fuente
55
mkfifosolo crea la tubería con nombre, sin ningún contenido. Por lo tanto, debe escribirlo usted mismo (por ejemplo mkfifo mypipe; ls > mypipe). Y sí, las escrituras en la tubería se bloquearán hasta que se lea algún proceso de la tubería.
crater2150
66
No hay una tubería con nombre aquí. /dev/fd/63Es una tubería anónima.
Gilles 'SO- deja de ser malvado'
1
@ crater2150, @Gilles / dev / fd / 63 es de hecho una tubería con nombre. Comprueba esto con algo así file <(ls). El shell crea una tubería anónima, pero el descriptor de archivo se refleja como una tubería con nombre /dev/fd. Si se tratara de una tubería anónima, no tendría un nombre y no podría abrirse mediante un comando al que /dev/fd/63se pasa.
RV
2
@rv Sigue siendo una tubería anónima. El hecho de que haya un nombre de archivo que se refiera a esta tubería anónima no lo convierte en una tubería con nombre: una tubería con nombre es diferente, existe en algún lugar de un sistema de archivos, tiene permisos y propiedad, etc. Las entradas de /dev/fdpueden referirse a cualquier archivo descriptor, incluso tuberías anónimos y enchufes, tomas de corriente de red, segmentos de memoria compartida, etc.
Gilles 'SO- estar parada mal'
1
¿Por qué es 63 , sin embargo?
K3 --- rnc
-4

Usted malinterpreta tanto el lscomando como la redirección. lsenumera los archivos y directorios dados en la línea de comando, no creo que acepte ninguna entrada de stdin. Redirección > >>y <son formas de utilizar un archivo para dar entrada y recopilar salida.

ruibarbo
fuente
1
No hay redirección desde un archivo aquí. <(…)Es un proceso de sustitución.
Gilles 'SO- deja de ser malvado'
1
@IMSoP, como dijo Gilles, no es una tubería con nombre, es una tubería anónima. Es muy parecido x|yy casi idéntico al [num]<<REDIRECTde algunas conchas. En lo que difiere es la sustitución literal del shell del enlace fd, /dev/fd/63y etc., y lo que hace, o no hace, con stdin. Hazlo echo | readlink /dev/fd/0y compruébalo por ti mismo.
mikeserv
1
@IMSoP - eso es un devenlace - un archivo especial. puede hacer lo mismo con cualquier descriptor de archivo en la mayoría de los sistemas Linux, incluso lo típico |pipes, aunque no responderé por el comportamiento en otros lugares. entiendo de dónde vienes, pero una tubería con nombre es una cosa separada en sí misma: es una referencia del sistema de archivos a una tubería en el núcleo: una referencia normal del sistema de archivos, no un archivo de dispositivo.
mikeserv
1
@mikeserv Curiosamente, el manual de Bash menciona que funcionará en sistemas sin /dev/fd/*crear una tubería con nombre en otro lugar. Pero considero que /dev/fd/*es un mecanismo diferente al de una tubería con nombre propiamente dicho. Por cierto, la descripción de Wikipedia podría hacer una explicación de esta distinción.
IMSoP
1
@mikeserv Según otras referencias que encontré, es más simple que eso: si /dev/fd/*no está disponible, bash creará una tubería con nombre /tmpy la usará para la sustitución del proceso. No me parece tan extraño, simplemente haciendo que la funcionalidad esté disponible en tantos entornos como sea posible.
IMSoP