Pourquoi la substitution de processus entraîne-t-elle un fichier appelé / dev / fd / 63 qui est un canal?

40

J'essaie de comprendre les canaux nommés dans le contexte de cet exemple particulier.

Je tape <(ls -l)dans mon terminal et obtenir la sortie comme, bash: /dev/fd/63: Permission denied.

Si je tape cat <(ls -l), je pourrais voir le contenu du répertoire. Si je remplace le catavec echo, je pense avoir le nom du terminal (ou est-ce?).

echo <(ls -l)donne la sortie comme /dev/fd/63.

En outre, cet exemple de sortie n'est pas clair pour moi.

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

Cependant, si je donne, ls -l <()il me liste le contenu du répertoire.

Que se passe-t-il dans le cas du tuyau nommé?

Ramesh
la source

Réponses:

37

Lorsque vous le faites <(some_command), votre shell exécute la commande entre parenthèses et remplace le tout par un descripteur de fichier, connecté à la sortie standard de la commande. Il en /dev/fd/63va de même pour un tuyau contenant la sortie de votre appel ls.

Lorsque vous <(ls -l)obtenez une Permission deniederreur, parce que toute la ligne est remplacée par le tuyau, essayant en fait d'appeler /dev/fd/63comme une commande, ce qui n'est pas exécutable.

Dans votre deuxième exemple, cat <(ls -l)devient cat /dev/fd/63. Comme chat lit à partir des fichiers donnés en paramètres, vous obtenez le contenu. echod'autre part, sort ses paramètres "tels quels".

Le dernier cas que vous avez, <()est simplement remplacé par rien, car il n'y a pas de commande. Mais ce n'est pas cohérent entre les coquilles, en zsh vous obtenez toujours un tuyau (bien que vide).

Résumé : <(command)vous permet d'utiliser la sortie d'une commande, où vous auriez normalement besoin d'un fichier.

Edit: comme le fait remarquer Gilles , ce n'est pas un tuyau nommé, mais un tuyau anonyme. La principale différence est qu’il n’existe que, tant que le processus est en cours d’exécution, alors qu’un canal nommé (créé par exemple avec mkfifo) restera sans processus liés.

crater2150
la source
5
mkfifocrée uniquement le canal nommé, sans aucun contenu. Vous devez donc écrire vous-même (par exemple mkfifo mypipe; ls > mypipe). Et oui, les écritures sur le tuyau seront bloquées jusqu'à ce qu'un processus lise à partir du tuyau.
crater2150
6
Il n'y a pas de pipe nommée ici. /dev/fd/63est une pipe anonyme.
Gilles 'SO- arrête d'être méchant'
1
@ crater2150, @Gilles / dev / fd / 63 est en effet un tuyau nommé. Vérifiez cela avec quelque chose comme file <(ls). Le shell crée un canal anonyme, mais le descripteur de fichier est reflété sous forme de canal nommé /dev/fd. S'il s'agissait d'un canal anonyme, il n'aurait pas de nom et ne pourrait pas être ouvert par une commande à laquelle /dev/fd/63est passée.
RV
2
@rv C'est toujours un tuyau anonyme. Le fait qu'un nom de fichier faisant référence à ce canal anonyme n'en fait pas un canal nommé: un canal nommé est différent, il existe quelque part sur un système de fichiers, possède des autorisations et un droit de propriété, etc. Les entrées de /dev/fdpeuvent faire référence à n'importe quel fichier. Descripteur, même des tuyaux et des sockets anonymes, des sockets réseau, des segments de mémoire partagée, etc.
Gilles 'SO, arrête de faire le mal'
1
Pourquoi est-il 63 , cependant?
K3 --- rnc
-4

Vous comprenez mal la lscommande et la redirection. lsrépertorie les fichiers et les répertoires indiqués sur la ligne de commande, je ne pense pas qu’elle accepte les entrées de stdin. La redirection > >>et <les moyens d'utiliser un fichier pour entrer et collecter des sorties.

rhubarbdog
la source
1
Il n'y a pas de redirection à partir d'un fichier ici. <(…)est une substitution de processus.
Gilles 'SO- arrête d'être méchant'
1
@IMSoP - comme Gilles l'a dit - ce n'est pas un tuyau nommé - c'est un tuyau anonyme. C'est à peu près la même chose x|yet presque identique à celle [num]<<REDIRECTde certains coquillages. Ce qui est différent, c’est la substitution littérale du shell avec le lien fd - /dev/fd/63et cetera et ce qu’il fait - ou ne fait pas - avec stdin. Faites echo | readlink /dev/fd/0et voyez par vous-même.
mikeserv
1
@IMSoP - c'est un devlien - un fichier spécial. vous pouvez faire la même chose avec n'importe quel descripteur de fichier sur la plupart des systèmes Linux - même typique |pipes, bien que je ne garantisse pas le comportement ailleurs. Je comprends d'où vous venez, mais un tube nommé est une chose distincte en soi - c'est une référence de système de fichiers à un tube dans le noyau - une référence de système de fichiers normale , pas un fichier de périphérique.
mikeserv
1
@ mikeserv Il est intéressant de noter que le manuel de Bash mentionne que cela fonctionnera sur des systèmes sans /dev/fd/*créer un canal nommé ailleurs. Mais je prends l’argument qu’il /dev/fd/*s’agit d’un mécanisme différent de celui d’un tuyau nommé proprement dit. Incidemment, la description de Wikipedia pourrait être expliquée par cette distinction.
IMSoP
1
@mikeserv Selon d'autres références que j'ai trouvées, c'est plus simple que cela: si /dev/fd/*non disponible, bash crée un canal nommé /tmp, et l'utilise pour la substitution de processus. Cela ne me semble pas si étrange, mais de rendre la fonctionnalité disponible dans autant d'environnements que possible.
IMSoP