Come reindirizzare l'output su un file e stdout


989

In bash, chiamando foochiamerebbe qualsiasi output da quel comando sullo stdout.

La chiamata foo > outputreindirizzerebbe qualsiasi output da quel comando al file specificato (in questo caso 'output').

C'è un modo per reindirizzare l'output su un file e visualizzarlo su stdout?


3
Se qualcuno è appena arrivato qui alla ricerca di un errore di acquisizione dell'output su file, dai un'occhiata a - unix.stackexchange.com/questions/132511/…
Murphy,

2
Una nota sulla terminologia: quando si eseguono foo > outputi dati vengono scritti su stdout e stdout è il file denominato output. Cioè, scrivere sul file sta scrivendo su stdout. Stai chiedendo se è possibile scrivere sia su stdout che sul terminale.
William Pursell,

2
@WilliamPursell Non sono sicuro che i tuoi chiarimenti migliorino le cose :-) Che ne dici di questo: OP sta chiedendo se è possibile indirizzare lo stdout del programma chiamato sia su un file che sullo stdout del programma chiamante (quest'ultimo è lo stdout che il programma chiamato avrebbe ereditare se non è stato fatto nulla di speciale, ovvero il terminale, se il programma chiamante è una sessione bash interattiva). E forse vogliono anche dirigere lo stderr del programma chiamato in modo simile ("qualsiasi output da quel comando" potrebbe essere ragionevolmente interpretato nel senso di includere stderr).
Don Hatch, il

Risposte:


1381

Il comando desiderato si chiama tee:

foo | tee output.file

Ad esempio, se ti interessa solo stdout:

ls -a | tee output.file

Se vuoi includere stderr, esegui:

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

2>&1reindirizza il canale 2 (stderr / errore standard) nel canale 1 (stdout / output standard), in modo tale che entrambi siano scritti come stdout. Viene anche indirizzato al file di output specificato a partire dal teecomando.

Inoltre, se si desidera aggiungere al file di registro, utilizzare tee -acome:

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

173
Se OP vuole che "tutto l'output" venga reindirizzato, dovrai anche prendere stderr: "ls -lR / 2> & 1 | tee output.file"
James Brady

45
@evanmcdonnal La risposta non è sbagliata, potrebbe non essere abbastanza specifica o completa a seconda delle esigenze. Esistono certamente condizioni in cui potresti non voler salvare stderr come parte dell'output che viene salvato in un file. Quando ho risposto a questa domanda 5 anni fa, ho ipotizzato che l'OP volesse solo stdout, dal momento che ha menzionato stdout nell'argomento del post.
Zoredache,

3
Ah scusa, avrei potuto essere un po 'confuso. Quando l'ho provato non ho avuto nessun output, forse tutto sarebbe andato a stderr.
evanmcdonnal,

38
Usa l' -aargomento su teeper aggiungere il contenuto output.file, invece di sovrascriverlo:ls -lR / | tee -a output.file
kazy

16
Se lo stai utilizzando in $?seguito, verrà restituito il codice di stato tee, che probabilmente non è quello che desideri. Invece, puoi usare ${PIPESTATUS[0]}.
LaGoutte

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

2>&1scarica i flussi stderr e stdout. tee outfileprende il flusso che ottiene e lo scrive sullo schermo e nel file "outfile".

Questo è probabilmente ciò che la maggior parte delle persone sta cercando. La probabile situazione è che alcuni programmi o script stiano lavorando duramente da molto tempo e producano molto output. L'utente desidera controllarlo periodicamente per verificare l'avanzamento, ma desidera anche che l'output sia scritto in un file.

Il problema (specialmente quando si mescolano flussi stdout e stderr) è che si fa affidamento sui flussi scaricati dal programma. Se, ad esempio, tutte le scritture su stdout non vengono scaricate, ma tutte le scritture su stderr vengono scaricate, finiranno per finire in ordine cronologico nel file di output e sullo schermo.

È anche un male se il programma emette solo 1 o 2 righe ogni pochi minuti per segnalare i progressi. In tal caso, se l'output non è stato scaricato dal programma, l'utente non vedrebbe nemmeno alcun output sullo schermo per ore, perché nessuno verrebbe spinto attraverso il tubo per ore.

Aggiornamento: il programma unbuffer, parte del expectpacchetto, risolverà il problema del buffering. Ciò farà sì che stdout e stderr scrivano immediatamente sullo schermo e sul file e li mantengano sincronizzati quando vengono combinati e reindirizzati tee. Per esempio:

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

7
Qualcuno sa di un 'unbuffer' per osx?
John Mee,

7
Se non puoi usare unbuffer, i coreutils GNU includono uno strumento chiamato stdbuff che può essere usato per prevenire il buffering dell'output in questo modo$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter

1
Se stai usando OS X, nella maggior parte dei casi è leggermente più facile usare lo smorzatore, anche se non se vuoi passare i segnali al comando che stai eseguendo. Il mio commento era più rivolto agli utenti che si trovano su Linux, dove coreutils è molto probabilmente installato di default. @Ethan, vedere questa risposta se siete confusi sulla sintassi stdbuf: stackoverflow.com/a/25548995/942781
Peter

3
Nota che pythonha un'opzione integrata -uche non bufferizza l'output.
fabian789,

1
Salvagente assoluto per l'addestramento dei modelli ML in cui desidero accedere senza codice aggiuntivo ma vedere anche l'output nelle ore / giorni necessari per l'esecuzione, grazie!
rococò,

126

Un altro modo che funziona per me è

<command> |& tee  <outputFile>

come mostrato nel manuale di gnu bash

Esempio:

ls |& tee files.txt

Se si usa '| &', l' errore standard di command1 , oltre alla sua uscita standard , è collegato all'ingresso standard di command2 attraverso la pipe; è una scorciatoia per 2> & 1 |. Questo reindirizzamento implicito dell'errore standard sull'output standard viene eseguito dopo qualsiasi reindirizzamento specificato dal comando.

Per ulteriori informazioni, consultare il reindirizzamento


10
Se lo stai utilizzando in $?seguito, verrà restituito il codice di stato tee, che probabilmente non è quello che desideri. Invece, puoi usare ${PIPESTATUS[0]}.
LaGoutte

1
Questo metodo elimina l'output colorato della console, qualche idea?
shakram02,

Prova: unbuffer ls -l --color = auto | tee files.txt
Luciano Andress Martini

17

Puoi usare principalmente la soluzione Zoredache , ma se non vuoi sovrascrivere il file di output, dovresti scrivere tee con l'opzione -a come segue:

ls -lR / | tee -a output.file

11

Qualcosa da aggiungere ...

Il pacchetto unbuffer presenta problemi di supporto con alcuni pacchetti nelle versioni fedora e redhat unix.

Mettere da parte i problemi

Il seguito ha funzionato per me

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

Grazie ScDF e matthew i tuoi input mi hanno fatto risparmiare un sacco di tempo ..



3

Risposta bonus da quando questo caso d'uso mi ha portato qui:

Nel caso in cui sia necessario farlo come un altro utente

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

Si noti che l'eco avverrà mentre l'utente e la scrittura del file avverranno come "utente_unico" ciò che NON funzionerà è se si dovesse eseguire l'eco come "utente_un_utente" e reindirizzare l'output con >> "file_un_file" perché il reindirizzamento del file avverrà come te.

Suggerimento: tee supporta anche append con il flag -a, se è necessario sostituire una riga in un file come un altro utente, è possibile eseguire sed come l'utente desiderato.


2

< command > |& tee filename # questo creerà un file "nomefile" con lo stato del comando come contenuto, se un file esiste già rimuoverà il contenuto esistente e scriverà lo stato del comando.

< command > | tee >> filename # questo aggiungerà lo stato al file ma non stampa lo stato del comando su standard_output (schermo).

Voglio stampare qualcosa usando "echo" sullo schermo e aggiungere i dati che fanno eco a un file

echo "hi there, Have to print this on screen and append to a file" 

1

Puoi farlo per l'intero script usando qualcosa del genere all'inizio del tuo 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

Questo reindirizza gli output di stderr e stdout al file chiamato mylogfile e lascia tutto allo stdout allo stesso tempo .

Si usano alcuni stupidi trucchi:

  • utilizzare execsenza comando per impostare i reindirizzamenti,
  • utilizzare teeper duplicare output,
  • riavvia lo script con i reindirizzamenti desiderati,
  • usa un primo parametro speciale (un NULcarattere semplice specificato dalla $'string'notazione bash speciale) per specificare che lo script viene riavviato (nessun lavoro equivalente può essere usato dal tuo lavoro originale),
  • prova a preservare lo stato di uscita originale quando riavvii lo script usando l' pipefailopzione.

Brutto ma utile per me in determinate situazioni.


-13

tee è perfetto per questo, ma anche questo farà il lavoro

ls -lr / > output | cat output

10
Questo è un errore se l'output non esiste già e non fa quello che vuoi se lo fa, nel complesso è privo di senso. Forse intendevi ";" invece di "|" ?
Robert Gamble,

6
Anche se hai usato a ;, l'output sarebbe molto ritardato durante un comando lento.
Brad Koch,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.