¿Existe una utilidad Unix para anteponer marcas de tiempo a la entrada estándar?

StackOverflow https://stackoverflow.com/questions/21564

  •  09-06-2019
  •  | 
  •  

Pregunta

Terminé escribiendo un pequeño script rápido para esto en Python, pero me preguntaba si había una utilidad en la que pudiera introducir texto que antepusiera cada línea con algo de texto (en mi caso específico, una marca de tiempo).Lo ideal sería que el uso fuera algo como:

cat somefile.txt | prepend-timestamp

(Antes de responder sed, probé esto:

cat somefile.txt | sed "s/^/`date`/"

Pero eso solo evalúa el comando de fecha una vez cuando se ejecuta sed, por lo que se antepone incorrectamente la misma marca de tiempo a cada línea).

¿Fue útil?

Solución

Podría intentar usar awk:

<command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; fflush(); }'

Es posible que deba asegurarse de que <command> produce una salida almacenada en búfer de línea, es decirvacía su flujo de salida después de cada línea;la marca de tiempo awk add será el momento en que apareció el final de la línea en su tubo de entrada.

Si awk muestra errores, intente gawk en cambio.

Otros consejos

ts de másutils antepondrá una marca de tiempo a cada línea de entrada que le proporcione.También puedes formatearlo usando strftime.

$ echo 'foo bar baz' | ts
Mar 21 18:07:28 foo bar baz
$ echo 'blah blah blah' | ts '%F %T'
2012-03-21 18:07:30 blah blah blah
$ 

Para instalarlo:

sudo apt-get install moreutils

anotar, disponible a través de ese enlace o como annotate-output en el debian devscripts paquete.

$ echo -e "a\nb\nc" > lines
$ annotate-output cat lines
17:00:47 I: Started cat lines
17:00:47 O: a
17:00:47 O: b
17:00:47 O: c
17:00:47 I: Finished with exitcode 0

Resumiendo las respuestas dadas a la más simple posible:

unbuffer $COMMAND | ts

En Ubuntu, provienen de los paquetes expect-dev y moreutils.

sudo apt-get install expect-dev moreutils

¿Qué tal esto?

cat somefile.txt | perl -pne 'print scalar(localtime()), " ";'

A juzgar por su deseo de obtener marcas de tiempo en vivo, ¿tal vez desee realizar una actualización en vivo en un archivo de registro o algo así?Tal vez

tail -f /path/to/log | perl -pne 'print scalar(localtime()), " ";' > /path/to/log-with-timestamps

Solo voy a tirar esto por ahí:hay un par de utilidades en Daemon Tools llamado tai64n y tai64nlocal que están hechos para anteponer marcas de tiempo para registrar mensajes.

Ejemplo:

cat file | tai64n | tai64nlocal

La respuesta de Kieron es la mejor hasta ahora.Si tiene problemas porque el primer programa está almacenando en el búfer, puede usar el programa de eliminación del búfer:

unbuffer <command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; }'

Está instalado de forma predeterminada en la mayoría de los sistemas Linux.Si necesita construirlo usted mismo, es parte del paquete expect.

http://expect.nist.gov

Utilice el comando read(1) para leer una línea a la vez desde la entrada estándar, luego genere la línea precedida por la fecha en el formato que elija usando date(1).

$ cat timestamp
#!/bin/sh
while read line
do
  echo `date` $line
done
$ cat somefile.txt | ./timestamp

No soy un tipo de Unix, pero creo que puedes usar

gawk '{print strftime("%d/%m/%y",systime()) $0 }' < somefile.txt
#! /bin/sh
unbuffer "$@" | perl -e '
use Time::HiRes (gettimeofday);
while(<>) {
        ($s,$ms) = gettimeofday();
        print $s . "." . $ms . " " . $_;
}'

Aquí está mi solución awk (desde un sistema Windows/XP con MKS Tools instalado en el directorio C:\bin).Está diseñado para agregar la fecha y hora actuales en el formato mm/dd hh:mm al comienzo de cada línea después de haber obtenido esa marca de tiempo del sistema a medida que se lee cada línea.Por supuesto, podría usar el patrón BEGIN para recuperar la marca de tiempo una vez y agregar esa marca de tiempo a cada registro (de todos modos).Hice esto para etiquetar un archivo de registro que se estaba generando en la salida estándar con la marca de tiempo en el momento en que se generó el mensaje de registro.

/"pattern"/ "C\:\\\\bin\\\\date '+%m/%d %R'" | getline timestamp;
print timestamp, $0;

donde "patrón" es una cadena o expresión regular (sin las comillas) que debe coincidir en la línea de entrada, y es opcional si desea hacer coincidir todas las líneas de entrada.

Esto también debería funcionar en sistemas Linux/UNIX, simplemente elimine C\:\\bin\\ dejando la línea

             "date '+%m/%d %R'" | getline timestamp;

Esto, por supuesto, supone que el comando "fecha" lo lleva al comando estándar de visualización/establecimiento de fecha de Linux/UNIX sin información de ruta específica (es decir, la variable PATH de su entorno está configurada correctamente).

Mezclando algunas respuestas anteriores de natevw y Frank Ch.Eigler.

Tiene milisegundos, funciona mejor que llamar a un externo date comando cada vez y perl se pueden encontrar en la mayoría de los servidores.

tail -f log | perl -pne '
  use Time::HiRes (gettimeofday);
  use POSIX qw(strftime);
  ($s,$ms) = gettimeofday();
  print strftime "%Y-%m-%dT%H:%M:%S+$ms ", gmtime($s);
  '

Versión alternativa con descarga y lectura en bucle:

tail -f log | perl -pne '
  use Time::HiRes (gettimeofday); use POSIX qw(strftime);
  $|=1;
  while(<>) {
    ($s,$ms) = gettimeofday();
    print strftime "%Y-%m-%dT%H:%M:%S+$ms $_", gmtime($s);
  }'
$ cat somefile.txt | sed "s/^/`date`/"

puedes hacer esto (con ñu/sed):

$ some-command | sed "x;s/.*/date +%T/e;G;s/\n/ /g"

ejemplo:

$ { echo 'line1'; sleep 2; echo 'line2'; } | sed "x;s/.*/date +%T/e;G;s/\n/ /g"
20:24:22 line1
20:24:24 line2

Por supuesto, puedes utilizar otras opciones del programa. fecha.solo reemplaza date +%T con lo que necesitas.

La respuesta de caerwyn se puede ejecutar como una subrutina, lo que evitaría nuevos procesos por línea:

timestamp(){
   while read line
      do
         echo `date` $line
      done
}

echo testing 123 |timestamp

Descargo de responsabilidad:La solución que propongo no es una utilidad integrada en Unix.

Me enfrenté a un problema similar hace unos días.No me gustaban la sintaxis ni las limitaciones de las soluciones anteriores, así que rápidamente preparé un programa en Go para que hiciera el trabajo por mí.

Puedes consultar la herramienta aquí: hora previa

Hay ejecutables prediseñados para Linux, MacOS y Windows en el Lanzamientos sección del proyecto GitHub.

La herramienta maneja líneas de salida incompletas y tiene (desde mi punto de vista) una sintaxis más compacta.

<command> | preftime

No es ideal, pero pensé en compartirlo en caso de que ayude a alguien.

haciéndolo con date y tr y xargs en OSX:

alias predate="xargs -I{} sh -c 'date +\"%Y-%m-%d %H:%M:%S\" | tr \"\n\" \" \"; echo \"{}\"'"
<command> | predate

si quieres milisegundos:

alias predate="xargs -I{} sh -c 'date +\"%Y-%m-%d %H:%M:%S.%3N\" | tr \"\n\" \" \"; echo \"{}\"'"

pero tenga en cuenta que en OSX, la fecha no le ofrece la opción %N, por lo que deberá instalar gdate (brew install coreutils) y finalmente llegar a esto:

alias predate="xargs -I{} sh -c 'gdate +\"%Y-%m-%d %H:%M:%S.%3N\" | tr \"\n\" \" \"; echo \"{}\"'"

Si el valor que está anteponiendo es el mismo en cada línea, inicie emacs con el archivo, luego:

Control + <espacio>

al principio del archivo (para marcar ese lugar), luego desplácese hacia abajo hasta el principio de la última línea (Alt + > irá al final del archivo...lo que probablemente también implicará la tecla Shift, luego Ctrl + a para ir al principio de esa línea) y:

Control + X r t

Cuál es el comando para insertar en el rectángulo que acaba de especificar (un rectángulo de ancho 0).

2008-8-21 6:45 p.m. <entrar>

O lo que quieras anteponer...luego verá ese texto antepuesto a cada línea dentro del rectángulo de ancho 0.

ACTUALIZAR:Me acabo de dar cuenta de que no quieres la MISMA fecha, así que esto no funcionará...aunque es posible que puedas hacer esto en emacs con una macro personalizada un poco más complicada, pero aún así, es muy bueno conocer este tipo de edición de rectángulos...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top