Comment rediriger la sortie vers un fichier et une sortie standard

990

En bash, l'appel fooafficherait n'importe quelle sortie de cette commande sur la sortie standard.

L'appel foo > outputredirigerait toute sortie de cette commande vers le fichier spécifié (dans ce cas «sortie»).

Existe-t-il un moyen de rediriger la sortie vers un fichier et de l' afficher sur stdout?

SCdF
la source
3
Si quelqu'un vient de se retrouver ici à la recherche d'une capture d'erreur dans un fichier, jetez un œil à - unix.stackexchange.com/questions/132511/…
Murphy
2
Remarque sur la terminologie: lorsque vous exécutez, foo > outputles données sont écrites sur stdout et stdout est le fichier nommé output. Autrement dit, écrire dans le fichier, c'est écrire sur stdout. Vous demandez s'il est possible d'écrire à la fois sur stdout et sur le terminal.
William Pursell
2
@WilliamPursell Je ne suis pas sûr que vos éclaircissements améliorent les choses :-) Pourquoi: OP demande s'il est possible de diriger la sortie standard du programme appelé vers un fichier et la sortie standard du programme appelant (ce dernier étant la sortie standard que le programme appelé ferait hériter si rien de spécial n'a été fait, c'est-à-dire le terminal, si le programme appelant est une session bash interactive). Et peut-être qu'ils veulent également diriger stderr du programme appelé de la même manière ("toute sortie de cette commande" pourrait être raisonnablement interprétée comme signifiant inclure stderr).
Don Hatch

Réponses:

1382

La commande que vous souhaitez est nommée tee:

foo | tee output.file

Par exemple, si vous ne vous souciez que de la sortie standard:

ls -a | tee output.file

Si vous souhaitez inclure stderr, faites:

program [arguments...] 2>&1 | tee outfile

2>&1redirige le canal 2 (stderr / erreur standard) vers le canal 1 (stdout / sortie standard), de sorte que les deux soient écrits comme stdout. Il est également dirigé vers le fichier de sortie donné à partir de la teecommande.

De plus, si vous souhaitez ajouter au fichier journal, utilisez tee -acomme:

program [arguments...] 2>&1 | tee -a outfile
Zoredache
la source
173
Si OP veut que "toutes les sorties" soient redirigées, vous devrez également saisir stderr: "ls -lR / 2> & 1 | tee output.file"
James Brady
45
@evanmcdonnal La réponse n'est pas fausse, elle n'est peut-être pas suffisamment précise ou complète selon vos besoins. Il existe certainement des conditions dans lesquelles vous ne souhaitez pas que stderr fasse partie de la sortie enregistrée dans un fichier. Lorsque j'ai répondu à cela il y a 5 ans, j'ai supposé que le PO ne voulait que la sortie standard, car il avait mentionné la sortie standard dans le sujet de l'article.
Zoredache du
3
Ah désolé, j'aurais peut-être été un peu confus. Quand je l'ai essayé, je n'ai eu aucune sortie, peut-être que tout allait à stderr.
evanmcdonnal du
38
Utilisez l' -aargument on teepour ajouter du contenu à output.file, au lieu de l'écraser:ls -lR / | tee -a output.file
kazy
16
Si vous utilisez $?ensuite, il renverra le code d'état de tee, ce qui n'est probablement pas ce que vous voulez. Au lieu de cela, vous pouvez utiliser ${PIPESTATUS[0]}.
LaGoutte
501
$ program [arguments...] 2>&1 | tee outfile

2>&1vide les flux stderr et stdout. tee outfileprend le flux qu'il obtient et l'écrit à l'écran et dans le fichier "outfile".

C'est probablement ce que la plupart des gens recherchent. La situation probable est qu'un programme ou un script travaille dur pendant longtemps et produit beaucoup de résultats. L'utilisateur souhaite vérifier régulièrement sa progression, mais souhaite également que la sortie soit écrite dans un fichier.

Le problème (en particulier lors du mélange des flux stdout et stderr) est qu'il y a une dépendance à l'égard des flux qui sont vidés par le programme. Si, par exemple, toutes les écritures sur stdout ne sont pas vidées, mais toutes les écritures sur stderr sont vidées, elles finiront par ordre chronologique dans le fichier de sortie et à l'écran.

C'est également mauvais si le programme ne produit que 1 ou 2 lignes toutes les quelques minutes pour signaler la progression. Dans un tel cas, si la sortie n'était pas purgée par le programme, l'utilisateur ne verrait même aucune sortie à l'écran pendant des heures, car aucune ne serait poussée à travers le tuyau pendant des heures.

Mise à jour: le programme unbuffer, qui fait partie du expectpackage, résoudra le problème de mise en mémoire tampon. Cela entraînera stdout et stderr à écrire sur l'écran et le fichier immédiatement et à les garder synchronisés lorsqu'ils sont combinés et redirigés vers tee. Par exemple:

$ unbuffer program [arguments...] 2>&1 | tee outfile
Matthew Alpert
la source
7
Quelqu'un connaît-il un "tampon" pour osx?
John Mee
7
Si vous ne pouvez pas utiliser unbuffer, GNU coreutils inclut un outil appelé stdbuff qui peut être utilisé pour empêcher le tampon de sortie comme ça$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter
1
Si vous utilisez OS X, il est légèrement plus facile d'utiliser la sauvegarde sans tampon dans la plupart des cas, mais pas si vous souhaitez transmettre des signaux à la commande que vous exécutez. Mon commentaire était plus destiné aux utilisateurs qui sont sous Linux, où coreutils est probablement installé par défaut. @Ethan, voyez cette réponse si vous êtes confus au sujet de la syntaxe stdbuf: stackoverflow.com/a/25548995/942781
Peter
3
Notez qu'il pythona une option intégrée -uqui sort les tampons.
fabian789
1
Sauveteur absolu pour la formation de modèles ML où je veux me connecter sans code supplémentaire mais aussi voir la sortie au fil des heures / jours nécessaires pour fonctionner, merci!
rococo
126

Une autre façon qui fonctionne pour moi est,

<command> |& tee  <outputFile>

comme indiqué dans le manuel de gnu bash

Exemple:

ls |& tee files.txt

Si '| &' est utilisé, l' erreur standard de command1 , en plus de sa sortie standard , est connectée à l'entrée standard de command2 via le tuyau; c'est un raccourci pour 2> & 1 |. Cette redirection implicite de l'erreur standard vers la sortie standard est effectuée après toutes les redirections spécifiées par la commande.

Pour plus d'informations, reportez-vous à la redirection

tsenapathy
la source
10
Si vous utilisez $?ensuite, il renverra le code d'état de tee, ce qui n'est probablement pas ce que vous voulez. Au lieu de cela, vous pouvez utiliser ${PIPESTATUS[0]}.
LaGoutte
1
Cette méthode élimine la sortie de la console colorée, des idées?
shakram02
Essayez: unbuffer ls -l --color = auto | tee files.txt
Luciano Andress Martini
17

Vous pouvez principalement utiliser la solution Zoredache , mais si vous ne voulez pas écraser le fichier de sortie, vous devez écrire tee avec l'option -a comme suit:

ls -lR / | tee -a output.file
O.Badr
la source
11

Quelque chose à ajouter ...

Le paquet non tamponné a des problèmes de support avec certains paquets sous Fedora et les versions Unix de Redhat.

Mettre de côté les ennuis

La suite a fonctionné pour moi

bash myscript.sh 2>&1 | tee output.log

Merci ScDF & matthew vos contributions m'ont fait gagner beaucoup de temps ..

nitinr708
la source
7

L'utilisation tail -f outputdevrait fonctionner.

Chuck Phillips
la source
3

Réponse bonus puisque ce cas d'utilisation m'a amené ici:

Dans le cas où vous devez le faire comme un autre utilisateur

echo "some output" | sudo -u some_user tee /some/path/some_file

Notez que l'écho se produira lorsque vous et l'écriture du fichier se produira en tant que "some_user" ce qui ne fonctionnera PAS si vous exécutez l'écho en tant que "some_user" et redirigez la sortie avec >> "some_file" car la redirection de fichier se produira comme toi.

Astuce: tee prend également en charge l'ajout avec l'indicateur -a, si vous devez remplacer une ligne dans un fichier en tant qu'autre utilisateur, vous pouvez exécuter sed en tant qu'utilisateur souhaité.

jorfus
la source
2

< command > |& tee filename # cela créera un fichier "filename" avec le statut de la commande en tant que contenu, si un fichier existe déjà, il supprimera le contenu existant et écrit le statut de la commande.

< command > | tee >> filename # ceci ajoutera le statut au fichier mais il n'imprimera pas le statut de la commande sur standard_output (écran).

Je veux imprimer quelque chose en utilisant "echo" à l'écran et ajouter ces données en écho à un fichier

echo "hi there, Have to print this on screen and append to a file" 
kiran sai
la source
1

Vous pouvez le faire pour l'ensemble de votre script en utilisant quelque chose comme ça au début de votre script:

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

Cela redirige les sorties stderr et stdout vers le fichier appelé mylogfile et laisse tout aller à stdout en même temps .

Il est utilisé quelques astuces stupides:

  • utiliser execsans commande pour configurer les redirections,
  • utiliser teepour dupliquer les sorties,
  • redémarrez le script avec les redirections souhaitées,
  • utilisez un premier paramètre spécial (un NULcaractère simple spécifié par la $'string'notation bash spéciale) pour spécifier que le script est redémarré (aucun paramètre équivalent ne peut être utilisé par votre travail d'origine),
  • essayez de conserver l'état de sortie d'origine lors du redémarrage du script à l'aide de l' pipefailoption.

Moche mais utile pour moi dans certaines situations.

Bruno BEAUFILS
la source
-13

tee est parfait pour cela, mais cela fera aussi le travail

ls -lr / > output | cat output
Kal
la source
10
C'est une erreur si la sortie n'existe pas déjà et qu'elle ne fait pas ce que vous voulez si c'est le cas, dans l'ensemble c'est absurde. Peut-être que vous vouliez dire ";" au lieu de "|" ?
Robert Gamble
6
Même si vous utilisiez a ;, la sortie serait très retardée lors d'une commande lente.
Brad Koch