Comment passer la sortie d'une commande à plusieurs commandes?

20

En utilisant la substitution de processus ou en groupant et en canalisant, on peut passer la sortie ( stdout ) d'un ensemble de commandes comme entrée pour une autre commande.

Exemple :

wc < <(echo hi;echo bye)
(echo hi; bye) | wc

Mais y a-t-il le contraire?

Autrement dit, existe-t-il un moyen d'envoyer la sortie d'une commande comme entrée pour de nombreuses autres commandes sur une seule ligne ?

Quelque chose comme :

cat testfile | wc | tail -n 5

( Ne prenez pas les pipelines littéralement ). Ici, j'essaie de passer la sortie de cat testfileà la fois wcettail -n 5

Un autre exemple serait:

( pour obtenir le dernier mot d'une phrase )

echo "some random words"| wc -c | cut -f(out put of wc -c) (output of first echo)
Severus Tux
la source

Réponses:

21

Réponse rapide. Vous pouvez utiliser tee >(what_to_do) >(another_thing_to_do)pour continuer avec votre commande pour autant de choses différentes que vous voulez faire.

Exemple:

Sortie du fichier de test d'origine:

:~$ cat testfile.txt 
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616

Sortie avec teecommandes ajoutées:

:~$ cat testfile.txt | tee >(tail -1) >(wc) >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
      2      10      91
Serial Number:    TW0XFJWX550854187616

Chaque commande dans tee n'est que des commandes normales que vous utiliseriez sur la ligne de commande, comme l'ajout de >(head -1 | wc)travaux également.

:~$ cat testfile.txt | tee >(tail -1) >(head -1 | wc)  >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
      1       7      52
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
Serial Number:    TW0XFJWX550854187616

Ou vous pouvez également saisir le dernier mot de dire la dernière ligne en utilisant awkavec $NFavec un wccomme ceci:

:~$ cat testfile.txt | tail -1 | tee >(wc) >(awk '{print $NF}')
Serial Number:    TW0XFJWX550854187616
TW0XFJWX550854187616
      1       3      39

REMARQUE: l' ajout d'une |commande de canal à la fin peut remplacer à l'aide des multiples commandes de la teecommande. J'ai ici quelques exemples que j'ai testés:

Exemple 1 (commande Pipe tirant tous les derniers mots):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $NF}'
words
24
5
1

Exemple 2 (N'affiche pas la sortie des commandes wc. La commande Pipe saisit le 3ème mot.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $3}'
just

Exemple 3 (Saisir le 3e mot de la ligne d'écho. Commande Tee.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $3}')
This is just five words
just
24
5
1

Exemple 4 (en saisissant le dernier mot de la ligne d'écho. Commande Tee.):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $NF}')
This is just five words
words
24
5
1

J'espère que cela t'aides!

Terrance
la source
3
J'adore le tee et le café! '-)
Elder Geek
1
La déclaration sur l'ordre de la sortie entre les différents consommateurs de teeest fausse. La raison pour laquelle vous obtenez généralement la bonne commande est que sur une machine à faible charge, le premier processus consommateur s'exécute en premier. Sur une machine plus occupée, le premier consommateur peut être mis en veille avant d'imprimer quoi que ce soit.
Matei David
@MateiDavid Je ne peux pas prouver le contraire, alors je viens de supprimer la déclaration. Pas de biggie.
Terrance
2
Voir ma réponse. Mais plus sérieusement, teen'a aucune idée des consommateurs - ils sont créés par bashqui traite la ligne. Il bashsuffit de copier les descripteurs de fichiers ouverts. Au-delà de cela, plusieurs consommateurs écrivent dans des descripteurs de fichiers ouverts sur le même fichier. Le noyau s'en occupe, mais certainement l'ordre dans lequel ils sont apparus sur la bashligne de commande ne sera pas un facteur.
Matei David
17

Vous devez teediviser le flux en plusieurs parties. Essayer:

cat testfile | tee >(wc -l) >(wc -w) >(wc -c) | tail -n 5

Remarques:

  • Si plusieurs processus ( wc, tail) écrivent tous sur stdout:

    • Vous pourriez obtenir une sortie tronquée.

    • Il n'y a aucune garantie quant à l'ordre dans lequel leur sortie apparaîtra. Pour voir cela, essayez en sleep 1; wc -wtant que deuxième consommateur.

  • teese bloquera si l'une de ses destinations ne consomme pas le flux assez rapidement. Cela signifie que les destinations seront alimentées en entrée à une vitesse à peu près similaire (modulo la mise en mémoire tampon de taille fixe). Il n'y a pas de solution facile à cela, la seule alternative est d'enregistrer le flux dans un fichier et de le transmettre séparément aux consommateurs. Pour wcet tailce n'est pas un problème.

Pour le dernier mot, c'est plus simple à faire:

echo "some random words" | awk '{print $NF}'
Matei David
la source
5

Le moreutilspackage fournit la commande pee(fusion de pipe et tee, qu'avez-vous pensé?) Qui fait exactement cela.

Pour votre premier exemple, vous utiliseriez:

cat testfile | pee wc "tail -n 5"

Le deuxième exemple est plus compliqué car vous voulez passer deux entrées à la dernière commande. J'utiliserais probablement awkcomme les autres réponses.

Lien: https://joeyh.name/code/moreutils/

T. Verron
la source