Comment diriger la sortie standard tout en la gardant à l'écran? (et non vers un fichier de sortie)

234

Je voudrais diriger la sortie standard d'un programme tout en le gardant à l'écran.

Avec un exemple simple ( echoutilisez ici uniquement à des fins d'illustration):

$ echo 'ee' | foo
ee <- la sortie que j'aimerais voir

Je sais que tee pourrait copier stdout dans un fichier mais ce n'est pas ce que je veux.
$ echo 'ee' | tee output.txt | foo

J'ai essayé,
$ echo 'ee' | tee /dev/stdout | foomais cela ne fonctionne pas, car la sortie tee /dev/stdoutest dirigée versfoo

gentooboontoo
la source
6
Notez que cela echo 'ee' | tee /dev/stderrfonctionne cependant, donc si votre exigence "à l'écran" est satisfaite par stderr aussi, cela suffira.
nh2

Réponses:

344

Voici une solution qui fonctionne sur n'importe quelle implémentation Unix / Linux, en supposant qu'elle se soucie de suivre la POSIXnorme. Il fonctionne aussi sur certains environnements non Unix cygwin.

echo 'ee' | tee /dev/tty | foo

Référence: Les spécifications de base du groupe ouvert, numéro 7 IEEE Std 1003.1, 2013 Edition, §10.1 :

/ dev / tty

Associé au groupe de processus de ce processus, le cas échéant. Il est utile pour les programmes ou les procédures shell qui souhaitent être sûrs d'écrire des messages ou de lire des données depuis le terminal, quelle que soit la façon dont la sortie a été redirigée. Il peut également être utilisé pour les applications qui demandent le nom d'un fichier pour la sortie, lorsque la sortie tapée est souhaitée et il est fastidieux de savoir quel terminal est actuellement utilisé. Dans chaque processus, un synonyme du terminal de contrôle

Il a été signalé que certains environnements comme Google Colab ne sont pas implémentés /dev/ttyalors que leur ttycommande renvoyait un appareil utilisable. Voici une solution de contournement:

tty=$(tty)
echo 'ee' | tee $tty | foo

ou avec un ancien obus Bourne:

tty=`tty`
echo 'ee' | tee $tty | foo
jlliagre
la source
5
@static_rtti Pourquoi ignorez-vous année après année mes réponses à votre commentaire?
jlliagre
1
@PaulBissex /dev/ttyest un appareil Unix obligatoire. Courez-vous dans une prison BSD?
jlliagre
1
@PaulBissex C'est soit une implémentation soit un bug de configuration. Est / dev monté? Que montre "ls -l / dev / tty / dev / tty * / dev"? Voir lists.freebsd.org/pipermail/freebsd-bugs/2012-November/… forums.freebsd.org/threads/…
jlliagre
1
Et vous pouvez faire une cascade teecomme ceci: cat some.log | tee /dev/tty | tee -a other.log | grep -i 'foo' >> foo.log1) obtenir tout cela sur la console, 2) tout ajouter à un autre fichier, 3) obtenir les foolignes dans un fichier différent.
Jesse Chisholm
1
Google Colab n'en a pas /dev/tty, mais la sortie de ttyest utilisable.
Tom Hale
69

Une autre chose à essayer est:

echo 'ee' | tee >(foo)

C'est >(foo)une substitution de processus .

bmk
la source
1
que faire si je veux diriger la sortie de foo vers une autre barre?
Jack Tang
3
@JackTang - Je pense que toute nouvelle tuyauterie sur la sortie de foodevra faire partie de la substitution du processus. Voici un exemple:echo 'ee' | tee file.txt >(wc -c | tr -d ' ')
Nick Chammas
1
C'était la solution pour moi sur FreeBSD (no / dev / tty)
Paul Bissex
9
Chammas @ Nick, pour maintenir un pipeline normal, vous pouvez échanger les sorties de tee: echo 'ee' | tee >(cat) | foo | bar.
Vaelus
18

L'accès à "/ dev / stdout" est refusé sur certains systèmes, mais l'accès au terminal utilisateur est donné par "/ dev / tty". En utilisant "wc" pour "foo", les exemples ci-dessus fonctionnent correctement (sous linux, OSX, etc.) comme:

% echo 'Hi' | tee /dev/tty | wc Hi 1 1 3

Pour ajouter un décompte au bas d'une liste de fichiers correspondants, j'utilise quelque chose comme:
% ls [A-J]* | tee /dev/tty | wc -l

Pour éviter d'avoir à me souvenir de tout cela, je définis des alias:
% alias t tee /dev/tty
% alias wcl wc -l

pour que je puisse simplement dire:
% ls [A-J]* | t | wcl


POSTSCRIPT: Pour le jeu plus jeune, qui pourrait titrer sa prononciation comme "titty", je pourrais ajouter que "tty" était autrefois l'abréviation courante pour un terminal "télétype", qui utilisait un rouleau de papier jaune et avait des touches rondes qui souvent coincé.

user51527
la source
17

Essayer:

$ echo 'ee' | tee /dev/stderr | foo

Si l'utilisation de stderr est une option, bien sûr.

Jan
la source
8

vous devez d'abord déterminer le terminal associé à votre écran (ou l'écran sur lequel vous souhaitez que la sortie s'affiche):

tty

alors vous pouvez envoyer la sortie sur ce terminal et diriger l'autre copie via votre programme foo:

echo ee | tee /dev/pty/2 | foo
Michael Martinez
la source
1
oneliner: t = $ (tty) echo ee | tee $ t | foo | bar
Jack Tang
5
@JackTang C'est bien mieux mais tinutile. Vous pouvez utiliser echo ee | tee $(tty) | foomais il a toujours une commande inutile ( tty), étant donné /dev/ttyque cela fonctionne.
jlliagre