¿Cuál es el propósito de 'tee'?

90

Todos los usos teeque vi en mi vida fueron tales:

 do_something | tee -a logfile

O:

do_something_else | tee logfile

¿Está teeinventado para aquellos que no saben que puedes hacer lo mismo con las redirecciones de tubería de shell? Como:

do_something >> logfile

O:

do_something_else > logfile

Es prácticamente lo mismo y se requieren menos golpes de teclado para escribir. ¿Qué características ocultas no veo tee?

R Moog
fuente
62
¿Cómo no fue respondido esto por la primera línea de la página de manual "... y escribir en la salida estándar y archivos" ? Las respuestas son interesantes, pero hablar en términos generales de cómo las tuberías son útiles solo refuerza cómo esta Q parece demasiado amplia, y tal vez debería haberse cerrado.
Xen2050
3
@ Xen2050 No se puede culpar a una pregunta por una respuesta demasiado amplia. La pregunta es muy específica, al igual que la respuesta actual mejor calificada .
Jon Bentley
1
@JonBentley la pregunta no suena como "un problema específico con suficientes detalles para identificar una respuesta adecuada" (como se lee en el cuadro de diálogo de cierre). Suena así: "si su pregunta puede ser respondida por un libro completo, o tiene muchas respuestas válidas (pero no hay forma de determinar cuáles, si las hay, son correctas), entonces probablemente sea demasiado amplio para nuestro formato". (Fuente: Centro de ayuda )
Xen2050
44
@ Xen2050 ¿Estamos leyendo la misma pregunta? Me parece muy específico: ¿cuál es la diferencia entre el te y las tuberías? Se ha respondido adecuadamente usando dos oraciones. Lejos de todo un libro. El hecho de que algunas respuestas elijan ir por una tangente no tiene nada que ver con el alcance de la pregunta.
Jon Bentley
@ JonBentley: ¿Estamos leyendo la misma pregunta? R Moog tipo de tipo de implica una pregunta bastante bien enfocada: ¿cuál es la diferencia entre tee y la redirección de E / S ?   El hecho de que diga " redirecciones de tubería de shell como y " no es un punto a su favor, y es un argumento para cerrar como poco claro. Pero en realidad hace múltiples preguntas: "¿Cuál es el propósito de ?", "¿Está inventado para aquellos que no saben que puede hacer lo mismo con las redirecciones de tubería de shell?" Y "¿Qué características ocultas no veo ?". Al menos dos de esas preguntas son demasiado amplias. >>>teeteetee
G-Man

Respuestas:

242

Lo que no se ve es que do_something | tee -a logfilepone en la salida logfile y la salida estándar, mientras do_something >> logfilepone solamente en el archivo de registro.

El propósito de teees producir un escenario de entrada múltiple y salida única, al igual que en un cruce 'T'.

EDITAR

Ha habido comentarios sobre cómo teepermite un uso más descuidado de sudo. Esto viene al caso: cat, ddo tal vez mejor bufferproporcionar esta posibilidad con un mejor rendimiento, si no necesita las múltiples salidas. Úselo teepara lo que está diseñado, no para lo que "también puede hacer"

Eugen Rieck
fuente
37
La salida múltiple es la clave. teeincluso puede tomar múltiples argumentos y escribir en muchos archivos a la vez.
Kamil Maciorowski
20
Yo lo llamaría un accesorio de tubería en T , no un cruce (¿como en una intersección de carreteras?) Las cosas vienen de una manera y salen en ambos sentidos.
user253751
77
¿Cómo usaría catde una manera directa en lugar de, teepor ejemplo, en echo /var/work/core.%p | sudo tee /proc/sys/kernel/core_pattern? echo /var/work/core.%p | sudo cat > /proc/sys/kernel/core_patternno funciona, porque la redirección es procesada por el shell no sudo. En cuanto a dd, echo /var/work/core.%p | sudo dd of=/proc/sys/kernel/core_patternfunciona, pero a ddmenudo es una herramienta dominada capaz de hacer un gran daño, especialmente debajo sudo. En cuanto a buffer, no está instalado por defecto en ninguna de las distribuciones basadas en RedHat o Ubuntu que tengo a mano (o MacOS) ...
Digital Trauma
3
@EugenRieck Entiendo su punto de vista sobre la relación 1: n entre in: out como la función principal. Sin embargo, ni el incorporado catni el /bin/cattrabajo para mí en esta situación. No importa de dónde catprovenga: el >shell de nivel superior (no sudo) seguirá manejándolo. La ventaja de teemás caten esta situación es que permite que el archivo de salida se pase como un parámetro de línea de comandos (y no como un redireccionamiento). ddes sin duda una opción viable, aunque todavía estaría a favor teede esto
Digital Trauma el
3
@EugenRieck ¿Qué caparazón tiene caty teecomo incorporado? ¿Y qué versión de sudopuede ejecutar Shell Builtins?
wjandrea
118

Tee no es inútil

Tal vez lo sabías de todos modos? Si no, ¡sigue leyendo! O si sabe cómo funciona, pero no está seguro de por qué existe, salte al final para ver cómo encaja con la filosofía de Unix.

¿Qué es el propósito de tee?

En su forma más simple, toma datos en la entrada estándar y los escribe en la salida estándar y en uno (o más) archivos. Se ha comparado con una pieza en T de plomería en la forma en que divide una entrada en dos salidas (y dos direcciones).

Ejemplos

Tomemos su primer ejemplo:

do_something | tee -a logfile

Esto toma el resultado de do_somethingy lo agrega al archivo de registro, mientras que también lo muestra al usuario. De hecho, la página de Wikipediatee tiene este como el segundo ejemplo:

Para ver y agregar el resultado de un comando a un archivo existente:

  lint program.c | tee -a program.lint

Esto muestra la salida estándar del comando lint program.c en la computadora y al mismo tiempo agrega una copia al final del archivo program.lint. Si el archivo program.lint no existe, se crea.

El siguiente ejemplo tiene otro uso: escalada de permisos :

Para permitir la escalada de permisos:

cat ~/.ssh/id_rsa.pub | ssh admin@server "sudo tee -a /root/.ssh/authorized_keys2 > /dev/null"

Este ejemplo muestra que se usa tee para evitar una limitación inherente en el sudocomando. sudono puede canalizar la salida estándar a un archivo. Al descargar su flujo de salida estándar /dev/null, también suprimimos la salida reflejada en la consola. El comando anterior brinda al usuario root acceso actual a un servidor a través de ssh, al instalar la clave pública del usuario en la lista de autorizaciones de la clave del servidor.

¿O tal vez desea tomar la salida de un comando, escribirlo en algún lugar y también usarlo como entrada para otro comando?

También puede usar el comando tee para almacenar la salida de un comando a un archivo y redirigir la misma salida como entrada a otro comando.

El siguiente comando tomará una copia de seguridad de las entradas de crontab y pasará las entradas de crontab como una entrada al comando sed que hará la sustitución. Después de la sustitución, se agregará como un nuevo trabajo cron.

$ crontab -l | tee crontab-backup.txt | sed 's/old/new/' | crontab –

(crédito a los ejemplos de uso del comando Tee )

Tee trabaja con la filosofía de Unix:

Escriba programas que hagan una cosa y que lo hagan bien. Escribir programas para trabajar juntos. Escriba programas para manejar secuencias de texto, porque esa es una interfaz universal.

(Crédito a lo básico de la filosofía de Unix )

tee se adapta a todos estos:

  • hace una cosa: crea una copia extra de entrada
  • funciona con otros programas porque es el pegamento (o una pieza de plomería 'T' si lo prefiere) lo que permite que otros programas trabajen juntos como en los ejemplos anteriores
  • lo hace manipulando una secuencia de texto dada en la entrada estándar
bertieb
fuente
3
@ Joe: sudo tee -aes probablemente una innovación más reciente (la vi por primera vez en las guías / wikis de Ubuntu, especialmente para configurar cosas /proc/sys, porque cambiar a Ubuntu fue cuando cambié a un sudosistema basado (cómo Ubuntu está configurado de forma predeterminada) en lugar de usarlo sucon un contraseña de root). Creo que teees anterior sudo, por lo que no es una razón para teeexistir. No es necesario teepara eso, simplemente es más corto para escribir de forma interactiva que sudo sh -c 'cat > output'.
Peter Cordes
1
Con proyectiles modernos como bash, puede teealimentar dos tuberías, como foo | tee >(pipe2) | pipe1. Otra forma divertida es ffmpeg ... |& tee /dev/tty | sed 's/.*\r// > encode.logver las actualizaciones de la línea de estado de forma interactiva en el tty, mientras se eliminan las "líneas" que terminan con retorno de carro en lugar de nueva línea para el registro real. (es decir, filtrar las actualizaciones de la línea de estado). En general, puede pegar una tee /dev/ttyen cualquier parte de una tubería como una impresión de depuración.
Peter Cordes
2
Es menos una limitación de sudo con la que estás trabajando y más una limitación de la interpretación del shell de>. Cuando ejecuta un comando con sudo, su stdout se envía de vuelta a su programa de shell y las redirecciones adicionales con> se ejecutan con los permisos del shell. Si desea escribir con permisos elevados, necesita que la parte elevada de la tubería sea lo que hace la escritura. Hay una gran cantidad de formas de hacer esto dependiendo de exactamente qué efecto estás buscando. Si realmente quieres usar> algo como 'sudo bash -c "command> outfile"' hará el trabajo.
Perkins
Exactamente, @Perkins. El shell analiza >y configura la redirección antes de que sudo incluso sea exec'd', por lo que definitivamente no es una limitación de sudo que no maneje cosas que nunca ve. :) Normalmente trato de referirme a esto como "el flujo de trabajo de sudo" o algún término similar cuando lo estoy explicando, en lugar de describir sudo.
dannysauer
sudo tee -aEn mi humilde opinión es un abuso de tee. Use sudo cat, sudo ddo (con el mejor rendimiento en muchos casos) sudo buffersi no necesita las múltiples salidas.
Eugen Rieck
70

Es prácticamente lo mismo y se requieren menos golpes de teclado para escribir.

No es lo mismo en absoluto ...

Lo siguiente parece ser algo equivalente, pero no lo son:

$ echo "hi" > test.txt
$ echo "hi" | tee test.txt
hi

La diferencia crítica es que el primero ha escrito los datos solo en el archivo nombrado, mientras que el segundo ha escrito hien el terminal ( stdout) y el archivo nombrado, como se muestra a continuación:

redirigir vs tee


teele permite escribir los datos en un archivo y usarlos en una tubería hacia adelante, lo que le permite hacer cosas útiles, como mantener los datos a mitad de camino a través de una tubería:

grep '^look ' interesting_file.txt \
  | tee interesting_lines.txt \
  | sort

O bien, puede escribir en un archivo con privilegios elevados, sin otorgarle a la tubería privilegios elevados (aquí echose ejecuta como el usuario, mientras teeescribe en el archivo como root):

echo 0 \
  | sudo tee /proc/sys/net/ipv4/ip_forward

Con tee, puede escribir en muchos archivos ( y stdout ):

echo "hi" \
  | tee a.txt b.txt

También es posible utilizar execcon teegrabar toda la producción de una secuencia de comandos en un archivo, al tiempo que permite un observador ( stdout) para ver los datos:

exec > >( tee output.log )
Attie
fuente
2
No hay que olvidar exec > >(tee "$LOGFILE") 2>&1en un script bash que permite que el script genere stdout y stderr a ambos, stdout y al archivo señalado por $LOGFILE.
rexkogitans
@rexkogitans 2> & 1 ¿no es esa sintaxis de lote de cmd?
dmb
@dmb: es la sintaxis de shell para "enviar stderr (= 2) al mismo lugar que stdout (= 1)"
psmears
@rexkogitans Realmente fue una pregunta justa, realmente no puedo saber que no has usado "Windoze" en una década. Solía 2>&1soltar la salida y errar en archivos txt en Windows.
dmb
1
@dmb Lo siento por sonar grosero. Se trata del comentario de psmears. Obviamente, Windows adoptó el estilo Unix aquí.
rexkogitans
27

Esta es una camiseta:
ingrese la descripción de la imagen aquí

Un accesorio de tubería en forma de T. Tiene una entrada y dos salidas separadas.
En otras palabras, divide un tubo en dos; como un tenedor en el camino

Del mismo modo, teees una tubería ( |) que le permite redirigir su entrada estándar a dos salidas separadas.


Ejemplo
Por ejemplo, escribe ls /.
Obtendrá una salida que se parece a:

Applications    Network     Users       bin        dev      net      private    tmp         var
Library         System      Volumes     cores      etc      home     opt        sbin        usr

Redireccione la salida a un archivo de texto ls / > ls.txt, y no se muestra ninguna salida en el shell, solo en el archivo de texto resultante.

¿Quiere ver el resultado Y pasarlo a un archivo de texto al mismo tiempo?
Agregue un teea su pipa ( |) es decir:ls / | tee ls.txt


Compara los dos:

ls /          >          ls.txt
ls /        | tee        ls.txt
voces
fuente
44
+1 para la imagen que, como sabemos, vale más que mil palabras
Sergiy Kolodyazhnyy
Si hubiera elegido una pieza T de manguera de jardín, habría estado en línea con la metáfora original de Doug McIlroy.
JdeBP
@JdeBP Lo siento, no tengo idea de quién es. ¿Es el autor original de la utilidad o algo así? El flujo de datos y la corriente eléctrica física a menudo se comparan con los sistemas hidráulicos, pero probablemente lo sepas. De todos modos, simplemente elegí este estilo para mantenerlo súper simple. Realmente iba a hacer eso para mantenerlo familiar, pero la variedad de jardín tiende a tener más forma de Y y / o accesorios visualmente complicados para unir accesorios, etc. Sin embargo, es esencialmente lo mismo.
voces
18

No. Resulta que mencionas uno de los pocos ejemplos en los que puedes redirigir al archivo usando >y >>operadores.

Pero Tee puede hacer mucho más. Debido a que te diriges a él, puedes hacerlo a otra cosa.

Un buen ejemplo aparece en la página de Wikipedia :

find "4DOS" wikipedia.txt | tee 4DOS.txt | sort > 4DOSsorted.txt

Básicamente, puede canalizar a Tee, por lo que luego puede canalizar desde Tee a otra cosa. Si todo lo que quiere hacer es escribir un archivo de registro, sí, entonces realmente no necesita Tee.

LPChip
fuente
17

teeEstá lejos de ser inútil. Lo uso todo el tiempo y me alegro de que exista. Es una herramienta muy útil si tiene una tubería que desea dividir. Un ejemplo muy simple es que tiene algún directorio $dque desea tar y también quiere hacer hash porque es paranoico (como yo) y no confía en el medio de almacenamiento para mantener los datos de manera confiable. Usted podría escribir en el disco primero y luego desmenuzar, pero eso sería un error si el archivo está dañado antes de que sea hash. Además, tendría que leerlo y si trabaja en archivos de varios cientos de GB de tamaño, sabrá que realmente no desea volver a leerlos si no es necesario.

Entonces, lo que hago es simplemente esto:

tar -c "$d" | tee >(sha256sum) >(cat > "$d"".tar") > /dev/null

Crea la bola de alquitrán y la canaliza en T, que luego la canaliza a dos subcapas, en una de las cuales está en hash y en la otra está escrita en el disco.

También es excelente si desea realizar varias operaciones en un archivo grande:

< file.tar.gz tee >(sha256sum) >(tar -xz) /other/storage/location/file.tar.gz > /dev/null

Lee el archivo una vez, lo codifica (para que pueda verificar si todavía está como debería), lo extrae y lo copia en una ubicación diferente. No es necesario leerlo tres veces para eso.

UTF-8
fuente
3
Nitpick: teeno crea las subcapas; el shell de llamada se ejecuta sha5sumy catconecta su salida a los descriptores de archivo que se pasan a tee. Además, un uso inútil de cat; puede usar la redirección de entrada para teeleer directamente file.tar.gz.
chepner
@chepner Tienes razón sobre la primera interjección pero estás completamente equivocado sobre la segunda. Me gusta escribir mis líneas en orden, por lo que denotar la entrada a la derecha es terrible para la legibilidad y hacerlo es claramente objetivamente inferior a mi método y no es una preferencia subjetiva mía. cates amor. cates la vida.
UTF-8
66
También puede escribir < file.tar.gz tee >(sha256sum) ...si le preocupa el orden léxico de las redirecciones. Eso no cambia el hecho de que no hay necesidad de un proceso completamente separado solo para alimentar un solo archivo tee.
chepner
1
@chepner Genial, gracias! Aprendí algo hoy. :)
UTF-8
1
El costo de comenzar cat es relativamente bajo. El costo de 100 GiB adicionales de llamadas al sistema de escritura + lectura definitivamente desperdicia tiempo de CPU adicional y ancho de banda de memoria para su ejemplo propuesto de un archivo enorme. Recuerde que el ancho de banda de la memoria es un recurso compartido en todos los núcleos, sin mencionar la contaminación adicional de la memoria caché L3 de esa copia. En un x86 con la mitigación Specter + Meltdown habilitada, las llamadas al sistema son más caras de lo que solían ser. Estás utilizando una cantidad considerable de tiempo extra de CPU en el transcurso de esa copia. Tampoco >(cat > foo)es más fácil de entender que foo, en mi opinión.
Peter Cordes
12

Nitpick en la respuesta de @ bertieb que dice Este ejemplo muestra que tee se está utilizando para evitar una limitación inherente en el comando sudo. sudo no puede canalizar la salida estándar a un archivo.

No existe una limitación inherente, solo un malentendido sobre cómo se procesa el comando.

Ejemplo:

sudo echo 0 > /proc/sys/net/ipv4/ip_forward

El shell actual analiza la línea de comando. Encuentra la redirección de salida y la realiza. Luego ejecuta el comando, que es el sudoy proporciona la línea de comando restante como argumentos para el comando ejecutado. Si el shell actual no tiene permisos de root, la redirección de salida fallará.

echo 0 | sudo tee /proc/sys/net/ipv4/ip_forward

Esto funciona porque la redirección de salida se difiere al teecomando, que en ese momento tiene permisos de root porque se ejecutó a través de sudo.

sudo bash -c "echo 0 > /proc/sys/net/ipv4/ip_forward"

Esto funciona porque el shell que realiza la redirección tiene permisos de root.

Studog
fuente
2
Además, es posible que necesite sudoel comando, pero no para el archivo que sale y la redirección funciona bien:sudo foo-needs-privilege > /tmp/this-output-file-doesnt
Dennis Williamson
10

Como otras personas han mencionado, la salida de tubería al teecomando escribe esa salida tanto en un archivo como en stdout.

A menudo lo uso teecuando quiero capturar la salida de un comando que tarda mucho tiempo en ejecutarse, pero también quiero inspeccionar visualmente la salida a medida que el comando la pone a disposición. De esa manera, no tengo que esperar a que el comando termine de ejecutarse antes de inspeccionar la salida.

Lo que no parece haberse mencionado todavía (a menos que me haya perdido) es que el teecomando también puede escribir en múltiples archivos a la vez. Por ejemplo:

ls *.png | tee a.txt b.txt

escribirá todos los *.pngarchivos en el directorio actual en dos archivos diferentes ( a.txty b.txt) a la vez.

De hecho, puede escribir texto en varios archivos diferentes a la vez de la teesiguiente manera:

$ tee --append a.txt b.txt c.txt d.txt
These lines are appended to four different files,
and are also written to stdout.
CTRL-D
JL
fuente
9

El uso más común de tee es ver el texto en el terminal al mismo tiempo que lo envía al archivo (o archivos). La redacción de su pregunta supone que solo escribe texto en los archivos de registro. Tengo scripts que escriben listas de nombres de archivo o nombres de directorio para activar archivos (para que otros scripts los procesen de forma asincrónica) y uso tee para enviar el mismo contenido a stdout. Todo stdout se dirige a los registros. Así que tengo mi texto donde lo quiero y tengo una entrada de registro que dice que hice esto, todo desde una sola declaración 'echo'

tee también es el mejor método en Unix para hacer múltiples archivos idénticos. Lo uso ocasionalmente para hacer múltiples archivos vacíos, como este ...

:|tee file01 file02 file03
Wil Young
fuente
55
¿por qué no touch? (más inmediatamente obvio lo que está sucediendo)
Attie
@Attie touchno truncará los archivos si ya existen, solo actualizará sus marcas de tiempo y dejará su contenido como está; pero teelos truncará. Además, hacer rm+ touches diferente a tee(piense en enlaces duros y enlaces simbólicos)
Matija Nalis
Entonces por qué no truncate -s 0? :-)
Attie
1

Imagínese, desea escribir la salida de un comando en un archivo de registro E imprimir en stdout. Cuando necesitas hacerlo al mismo tiempo, entonces necesitas tee.

Un caso de uso es tener scripts de compilación que escriban la compilación completa en stdout (por ejemplo, para Jenkins) pero cosas importantes al mismo tiempo en un archivo de registro separado (para correos electrónicos de resumen).

Realmente comenzarás a faltar teecuando tengas que hacer un script en Windows. No hay teey eso es realmente molesto.

domih
fuente
¿No es trivial crear?
Carreras de ligereza en órbita el
No es posible con lote / cmd ya que no puede dividir fácilmente una secuencia de salida de un comando.
domih
Correcto, pero como un programa de C ++ de tres líneas ...
Lightness Races in Orbit
1
La distribución de Windows unxutils tiene muchas herramientas de línea de comandos de Unix que, a diferencia de algunas distribuciones, no contaminan su entorno de ejecución de Windows. La mayor limitación está en el "glob" bing, que funciona de manera diferente en Unix / Linux que en Windows. "tee" es una de las herramientas disponibles.
cmm
2
No seas tonto, es 2018. Usa Powershell, sí tee. Cmd nunca fue pensado para secuencias de comandos serias, para eso estaba VBS. Powershell es la nueva herramienta de secuencias de comandos. Por supuesto, Cmd sigue siendo bastante poderoso, pero las herramientas de línea de comandos son bastante pocas.
Luaan