79 votes

Que signifie exactement <() en bash (et =() en zsh) ?

Je suis assez à l'aise avec bash, mais récemment je me suis retrouvé dans une substitution que je ne connaissais pas.

Qu'est-ce que c'est exactement <(command) dans bash ? Comment se compare-t-il à la =(command) dans zsh ?

Je comprends que cela a quelque chose à voir avec les descripteurs de fichiers par défaut. Dans mon ordinateur

echo <()

renvoie à /proc/self/fd/11 que j'ai découvert comme étant une copie du script STDOUT, mais cela me semble toujours aussi confus.

111voto

Dženan Points 306

C'est ce qu'on appelle la substitution de processus.

Le site <(list) est supportée par les deux, bash y zsh . Il fournit un moyen de transmettre la sortie d'une commande ( list ) à une autre commande en utilisant un tube ( | ) n'est pas possible. Par exemple, lorsqu'une commande ne prend tout simplement pas en charge les entrées provenant de STDIN ou vous avez besoin de la sortie de plusieurs commandes :

diff <(ls dirA) <(ls dirB)

<(list) connecte la sortie de list avec un fichier dans /dev/fd si le système le supporte, sinon un tube nommé (FIFO) est utilisé (ce qui dépend aussi du support du système ; aucun manuel ne dit ce qui se passe si les deux mécanismes ne sont pas supportés, probablement qu'il s'arrête avec une erreur). Le nom du fichier est alors passé comme argument sur la ligne de commande.


zsh soutient en outre =(list) en tant que remplaçant éventuel de <(list) . Avec =(list) un fichier temporaire est utilisé à la place du fichier dans /dev/fd ou une FIFO. Il peut être utilisé en remplacement de <(list) si le programme a besoin de lseek dans la sortie.

Selon le Manuel ZSH il pourrait également y avoir d'autres problèmes avec la façon <(list) travaux :

Le site = est utile car le formulaire /dev/fd et l'implémentation du tube nommé de <(...) ont des inconvénients. Dans le premier cas, certains programmes peuvent fermer automatiquement le descripteur de fichier en question avant d'examiner le fichier sur la ligne de commande, notamment si cela est nécessaire pour des raisons de sécurité, comme lorsque le programme est exécuté en setuid. Dans le second cas, si le programme n'ouvre pas réellement le fichier, le sous-shell qui tente de lire ou d'écrire dans le pipe va (dans une implémentation typique, différents systèmes d'exploitation peuvent avoir un comportement différent) se bloquer pour toujours et devra être tué explicitement. Dans les deux cas, le Shell fournit réellement l'information en utilisant un tube, de sorte que les programmes qui s'attendent à lseek (voir la page de manuel lseek(2) ) sur le fichier ne fonctionnera pas.

21voto

Abbas Points 3737

Notez qu'il s'agit d'une réponse bash, pas zsh.

Il y a des cas dans bash où vous ne pouvez pas utiliser les pipes :

some_command | some_other_command

parce que les pipes introduisent des sous-coques pour chaque composant du pipeline, lorsque les sous-coques sortent, tous les effets secondaires sur lesquels vous vous reposiez disparaissent. Par exemple, cet exemple artificiel :

cat file | while read line; do ((count++)); done
echo $count

affichera une ligne vierge, car l'option $count n'existe pas dans le Shell actuel.

Un coup d'éclat substitution de processus vous permet d'éviter cette énigme en vous permettant de lire la sortie de "some_command" comme vous le feriez à partir d'un fichier.

while read line; do ((count++)); done < <(cat file)
# ....................................1.2
echo $count   # the variable *does* exist in the current shell

(1) est une redirection d'entrée normale. (2) est le début de la <() syntaxe de substitution de processus.

1voto

MrsFixit Points 11

Une autre différence entre =(command) & <(command) dans zsh est l'exécution synchrone vs asynchrone :

date & \
diff =(sleep 4; date) =(sleep 5; date) & \
diff <(sleep 4; date) <(sleep 5; date) &

Sun 29 Nov 2020 08:16:01 AEDT
[1]    41717 done       date

$ 1c1
< Sun 29 Nov 2020 08:16:05 AEDT
---
> Sun 29 Nov 2020 08:16:06 AEDT

[3]  + 41719 exit 1     diff <(sleep 4; date) <(sleep 5; date)

$ 1c1
< Sun 29 Nov 2020 08:16:05 AEDT
---
> Sun 29 Nov 2020 08:16:10 AEDT

[2]  + 41718 exit 1     diff =(sleep 4; date) =(sleep 5; date)

... mais je ne sais pas si cela a été fait à dessein ou non, car je ne vois pas de raison impérieuse d'en avoir =() fonctionnent de manière synchrone.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X