web-dev-qa-db-fra.com

Pseudo-fichiers pour les données temporaires

Je souhaite souvent alimenter des données de chaîne relativement courtes (qui pourraient être plusieurs lignes cependant) vers des programmes en ligne de commande qui n'acceptent que les entrées de fichiers (par exemple wdiff) de manière répétée. Bien sûr, je peux créer un ou plusieurs fichiers temporaires, y enregistrer la chaîne et exécuter la commande avec le nom de fichier comme paramètre. Mais il me semble que cette procédure serait très inefficace si les données sont réellement écrites sur le disque et pourrait également endommager le disque plus que nécessaire si je répète cette procédure plusieurs fois, par exemple si je veux alimenter wdiff en une seule ligne de longs fichiers texte. Existe-t-il un moyen recommandé de contourner cela, par exemple en utilisant des pseudo-fichiers tels que des canaux pour stocker temporairement les données sans réellement les écrire sur le disque (ou en les écrivant uniquement si elles dépassent une longueur critique). Notez que wdiff prend deux arguments et, pour autant que je sache, il ne sera pas possible d'alimenter les données en faisant quelque chose comme wdiff <"text".

108
highsciguy

Utilisez un nommé pipe . À titre d'illustration:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

Le -e indique à echo d'interpréter correctement l'échappement de la nouvelle ligne (\n). Cela bloquera, c'est-à-dire que votre shell se bloquera jusqu'à ce que quelque chose lise les données du tube.

Ouvrez un autre shell quelque part et dans le même répertoire:

cat fifo

Vous lirez l'écho, qui libérera l'autre Shell. Bien que le canal existe en tant que nœud de fichier sur le disque, les données qui le traversent n'existent pas; tout se passe dans la mémoire. Vous pouvez avoir un arrière-plan (&) l'écho.

Le canal a un tampon 64k (sous linux) et, comme un socket, bloquera l'écrivain lorsqu'il sera plein, vous ne perdrez donc pas de données tant que vous ne tuez pas prématurément l'écrivain.

58
goldilocks

Dans Bash, vous pouvez utiliser la syntaxe de redirection command1 <( command0 ), qui redirige la sortie standard de command0 Et la transmet à un command1 Qui prend un nom de fichier comme argument de ligne de commande. Cela s'appelle ( substitution de processus .

Certains programmes qui prennent des arguments de ligne de commande de nom de fichier ont en fait besoin d'un vrai fichier à accès aléatoire, donc cette technique ne fonctionnera pas pour ceux-ci. Cependant, cela fonctionne très bien avec wdiff:

user@Host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}

En arrière-plan, cela crée un FIFO, dirige la commande à l'intérieur du <( ) vers le FIFO et transmet le descripteur de fichier du FIFO comme argument. Pour voir ce qui se passe, essayez de l'utiliser avec echo pour imprimer l'argument sans rien faire avec:

user@Host:/path$ echo <( echo hello )
/dev/fd/63

La création d'un canal nommé est plus flexible (si vous voulez écrire une logique de redirection compliquée en utilisant plusieurs processus), mais à de nombreuses fins, cela suffit et est évidemment plus facile à utiliser.

Il y a aussi la syntaxe >( ) pour quand vous voulez l'utiliser comme sortie, par ex.

$ someprogram --logfile >( gzip > out.log.gz )

Voir aussi Aide-mémoire des redirections Bash pour les techniques associées.

143
Mechanical snail

wdiff est un cas particulier car il nécessite 2 arguments de nom de fichier, mais pour toutes les commandes qui ne nécessitent qu'un seul argument et qui refusent obstinément de prendre autre chose qu'un argument de nom de fichier, il y a 2 options:

  • Le nom de fichier "-" (c'est-à-dire un signe moins) fonctionne environ la moitié du temps. Cela semble dépendre de la commande en question et si le développeur de la commande intercepte ce cas et le gère comme prévu. par exemple.

    $> ls | chat -

  • Il existe un fichier psuedo nommé/dev/stdin qui existe sous linux et peut être utilisé si un nom de fichier est absolument requis par une commande. Cela est plus susceptible de fonctionner car il ne nécessite aucune gestion de nom de fichier spéciale à partir de la commande. Si un fifo fonctionne, ou si la méthode bash substitution de processus fonctionne, cela devrait également fonctionner et n'est pas spécifique à Shell. par exemple.

    $> ls | chat/dev/stdin

11
dabuntu