Cómo redirigir la salida a un archivo y stdout

990

En bash, llamar foomostrará cualquier salida de ese comando en el stdout.

Llamar foo > outputredirigiría cualquier salida de ese comando al archivo especificado (en este caso, 'salida').

¿Hay alguna manera de redirigir la salida a un archivo y mostrarlo en stdout?

SCdF
fuente
3
Si alguien acaba de terminar aquí buscando capturar la salida del error en el archivo, eche un vistazo a - unix.stackexchange.com/questions/132511/…
Murphy
2
Una nota sobre terminología: cuando ejecuta foo > outputlos datos se escribe en stdout y stdout es el archivo llamado output. Es decir, escribir en el archivo es escribir en stdout. Usted pregunta si es posible escribir tanto en stdout como en la terminal.
William Pursell
2
@WilliamPursell No estoy seguro de que su aclaración mejora las cosas :-) ¿Qué tal esto: OP está preguntando si es posible dirigir la llamada del programa de salida estándar a la vez un archivo y el del programa llamando la salida estándar (siendo esta última la salida estándar que el programa llamado haría heredar si no se hizo nada especial; es decir, el terminal, si el programa que realiza la llamada es una sesión bash interactiva). Y tal vez también quieran dirigir el stderr del programa llamado de manera similar ("cualquier salida de ese comando" podría interpretarse razonablemente como que incluye stderr).
Don Hatch

Respuestas:

1382

El comando que desea se llama tee:

foo | tee output.file

Por ejemplo, si solo te importa stdout:

ls -a | tee output.file

Si desea incluir stderr, haga:

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

2>&1redirige el canal 2 (stderr / error estándar) al canal 1 (stdout / salida estándar), de modo que ambos se escriben como stdout. También se dirige al archivo de salida dado a partir del teecomando.

Además, si desea agregar al archivo de registro, use tee -acomo:

program [arguments...] 2>&1 | tee -a outfile
Zoredache
fuente
173
Si OP quiere que se redirija "toda la salida", también deberá tomar stderr: "ls -lR / 2> & 1 | tee output.file"
James Brady el
45
@evanmcdonnal La respuesta no es incorrecta, puede que no sea lo suficientemente específica o completa según sus requisitos. Ciertamente, existen condiciones en las que es posible que no desee stderr como parte de la salida que se guarda en un archivo. Cuando respondí esto hace 5 años, asumí que el OP solo quería stdout, ya que mencionó stdout en el tema de la publicación.
Zoredache
3
Ah lo siento, podría haber estado un poco confundido. Cuando lo probé simplemente no obtuve salida, tal vez todo iba a stderr.
evanmcdonnal
38
Use el -aargumento teepara agregar contenido a output.file, en lugar de sobrescribirlo:ls -lR / | tee -a output.file
kazy
16
Si está usando $?después, devolverá el código de estado de tee, que probablemente no sea lo que desea. En cambio, puedes usar ${PIPESTATUS[0]}.
LaGoutte
501
$ program [arguments...] 2>&1 | tee outfile

2>&1vuelca las secuencias stderr y stdout. tee outfiletoma la transmisión que recibe y la escribe en la pantalla y en el archivo "archivo externo".

Esto es probablemente lo que la mayoría de la gente está buscando. La situación probable es que algún programa o script esté trabajando duro durante mucho tiempo y produciendo una gran cantidad de resultados. El usuario quiere verificar periódicamente el progreso, pero también quiere que la salida se escriba en un archivo.

El problema (especialmente cuando se mezclan flujos stdout y stderr) es que el programa confía en que los flujos se descarguen. Si, por ejemplo, todas las escrituras en stdout no están enjuagadas, pero todas las escrituras en stderr están enjuagadas, entonces terminarán sin orden cronológico en el archivo de salida y en la pantalla.

También es malo si el programa solo genera 1 o 2 líneas cada pocos minutos para informar el progreso. En tal caso, si el programa no descargara la salida, el usuario ni siquiera vería ninguna salida en la pantalla durante horas, ya que ninguna de ellas pasaría por la tubería durante horas.

Actualización: el programa unbuffer, parte del expectpaquete, resolverá el problema de almacenamiento en búfer. Esto hará que stdout y stderr escriban en la pantalla y el archivo inmediatamente y los mantengan sincronizados cuando se combinen y se redirijan a ellos tee. P.ej:

$ unbuffer program [arguments...] 2>&1 | tee outfile
Matthew Alpert
fuente
77
¿Alguien sabe de un 'unbuffer' para osx?
John Mee
77
Si no puede utilizar unbuffer, GNU coreutils incluye una herramienta llamada stdbuff que se puede utilizar para evitar el almacenamiento en búfer de salida como tal$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter
1
Si está utilizando OS X, es marginalmente más fácil usar unbuffer en la mayoría de los casos, aunque no si desea pasar señales al comando que está ejecutando. Mi comentario estaba más dirigido a los usuarios que están en Linux, donde es muy probable que coreutils esté instalado de manera predeterminada. @ Ethan, mira esta respuesta si estás confundido acerca de la sintaxis de stdbuf: stackoverflow.com/a/25548995/942781
Peter
3
Tenga en cuenta que pythontiene una opción integrada -uque destraba la salida.
fabian789
1
Salvavidas absoluto para entrenar modelos ML donde quiero iniciar sesión sin código adicional pero también ver el resultado durante las horas / días que lleva correr, ¡gracias!
rococó
126

Otra forma que funciona para mí es,

<command> |& tee  <outputFile>

como se muestra en el manual de gnu bash

Ejemplo:

ls |& tee files.txt

Si se usa '| &', el error estándar del comando1 , además de su salida estándar , se conecta a la entrada estándar del comando2 a través de la tubería; es la abreviatura de 2> y 1 |. Esta redirección implícita del error estándar a la salida estándar se realiza después de cualquier redirección especificada por el comando.

Para obtener más información, consulte redirección

tsenapatía
fuente
10
Si está usando $?después, devolverá el código de estado de tee, que probablemente no sea lo que desea. En cambio, puedes usar ${PIPESTATUS[0]}.
LaGoutte
1
Este método descarta la salida de consola de color, ¿alguna idea?
shakram02
Prueba: unbuffer ls -l --color = auto | tee files.txt
Luciano Andress Martini
17

Principalmente puede usar la solución Zoredache , pero si no desea sobrescribir el archivo de salida, debe escribir tee con la opción -a de la siguiente manera:

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

Algo para agregar ...

El paquete unbuffer tiene problemas de soporte con algunos paquetes bajo Fedora y Redhat Unix.

Dejando de lado los problemas

Siguiente funcionó para mí

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

Gracias SCDF y matthew sus entradas me salvaron mucho tiempo ..

nitinr708
fuente
7

Usar tail -f outputdebería funcionar.

Chuck Phillips
fuente
3

Respuesta extra ya que este caso de uso me trajo aquí:

En el caso de que necesite hacer esto como otro usuario

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

Tenga en cuenta que el eco sucederá como usted y la escritura del archivo sucederá como "some_user", lo que NO funcionará es si tuviera que ejecutar el eco como "some_user" y redirigir la salida con >> "some_file" porque la redirección del archivo ocurrirá como tu.

Sugerencia: tee también admite agregar con el indicador -a, si necesita reemplazar una línea en un archivo como otro usuario, puede ejecutar sed como el usuario deseado.

jorfus
fuente
2

< command > |& tee filename # esto creará un archivo "nombre de archivo" con el estado del comando como contenido. Si ya existe un archivo, eliminará el contenido existente y escribirá el estado del comando.

< command > | tee >> filename # esto agregará estado al archivo pero no imprime el estado del comando en standard_output (pantalla).

Quiero imprimir algo usando "echo" en la pantalla y agregar esos datos repetidos a un archivo

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

Puede hacer eso para toda su secuencia de comandos utilizando algo así al principio de su secuencia de comandos:

#!/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

Esto redirige las salidas stderr y stdout al archivo llamado mylogfile y deja que todo vaya a stdout al mismo tiempo .

Se utilizan algunos trucos estúpidos:

  • usar execsin comando para configurar redirecciones,
  • utilizar teepara duplicar salidas,
  • reiniciar el script con las redirecciones deseadas,
  • use un primer parámetro especial (un simple NUL carácter especificado por la $'string'notación bash especial) para especificar que el script se reinicia (su trabajo original no puede usar ningún parámetro equivalente),
  • intente preservar el estado de salida original al reiniciar el script utilizando pipefail opción

Feo pero útil para mí en ciertas situaciones.

Bruno BEAUFILS
fuente
-13

la camiseta es perfecta para esto, pero esto también hará el trabajo

ls -lr / > output | cat output
kal
fuente
10
Eso es un error si la salida aún no existe y no hace lo que desea si lo hace, en general no tiene sentido. Quizás quisiste decir ";" en lugar de "|" ?
Robert Gamble, el
66
Incluso si usó a ;, la salida se retrasaría mucho durante un comando lento.
Brad Koch