Question

I ended up writing a quick little script for this in Python, but I was wondering if there was a utility you could feed text into which would prepend each line with some text -- in my specific case, a timestamp. Ideally, the use would be something like:

cat somefile.txt | prepend-timestamp

(Before you answer sed, I tried this:

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

But that only evaluates the date command once when sed is executed, so the same timestamp is incorrectly prepended to each line.)

Was it helpful?

Solution

Could try using awk:

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

You may need to make sure that <command> produces line buffered output, i.e. it flushes its output stream after each line; the timestamp awk adds will be the time that the end of the line appeared on its input pipe.

If awk shows errors, then try gawk instead.

OTHER TIPS

ts from moreutils will prepend a timestamp to every line of input you give it. You can format it using strftime too.

$ 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
$ 

To install it:

sudo apt-get install moreutils

annotate, available via that link or as annotate-output in the Debian devscripts package.

$ 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

Distilling the given answers to the simplest one possible:

unbuffer $COMMAND | ts

On Ubuntu, they come from the expect-dev and moreutils packages.

sudo apt-get install expect-dev moreutils

How about this?

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

Judging from your desire to get live timestamps, maybe you want to do live updating on a log file or something? Maybe

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

Just gonna throw this out there: there are a pair of utilities in daemontools called tai64n and tai64nlocal that are made for prepending timestamps to log messages.

Example:

cat file | tai64n | tai64nlocal

Kieron's answer is the best one so far. If you have problems because the first program is buffering its out you can use the unbuffer program:

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

It's installed by default on most linux systems. If you need to build it yourself it is part of the expect package

http://expect.nist.gov

Use the read(1) command to read one line at a time from standard input, then output the line prepended with the date in the format of your choosing using date(1).

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

I'm not an Unix guy, but I think you can use

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 . " " . $_;
}'

Here's my awk solution (from a Windows/XP system with MKS Tools installed in the C:\bin directory). It is designed to add the current date and time in the form mm/dd hh:mm to the beginning of each line having fetched that timestamp from the system as each line is read. You could, of course, use the BEGIN pattern to fetch the timestamp once and add that timestamp to each record (all the same). I did this to tag a log file that was being generated to stdout with the timestamp at the time the log message was generated.

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

where "pattern" is a string or regex (without the quotes) to be matched in the input line, and is optional if you wish to match all input lines.

This should work on Linux/UNIX systems as well, just get rid of the C\:\\bin\\ leaving the line

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

This, of course, assumes that the command "date" gets you to the standard Linux/UNIX date display/set command without specific path information (that is, your environment PATH variable is correctly configured).

Mixing some answers above from natevw and Frank Ch. Eigler.

It has milliseconds, performs better than calling a external date command each time and perl can be found in most of the servers.

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);
  '

Alternative version with flush and read in a loop:

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`/"

you can do this (with gnu/sed):

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

example:

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

of course, you can use other options of the program date. just replace date +%T with what you need.

caerwyn's answer can be run as a subroutine, which would prevent the new processes per line:

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

echo testing 123 |timestamp

Disclaimer: the solution I am proposing is not a Unix built-in utility.

I faced a similar problem a few days ago. I did not like the syntax and limitations of the solutions above, so I quickly put together a program in Go to do the job for me.

You can check the tool here: preftime

There are prebuilt executables for Linux, MacOS, and Windows in the Releases section of the GitHub project.

The tool handles incomplete output lines and has (from my point of view) a more compact syntax.

<command> | preftime

It's not ideal, but I though I'd share it in case it helps someone.

doing it with date and tr and xargs on OSX:

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

if you want milliseconds:

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

but note that on OSX, date doesn't give you the %N option, so you'll need to install gdate (brew install coreutils) and so finally arrive at this:

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

If the value you are prepending is the same on every line, fire up emacs with the file, then:

Ctrl + <space>

at the beginning of the of the file (to mark that spot), then scroll down to the beginning of the last line (Alt + > will go to the end of file... which probably will involve the Shift key too, then Ctrl + a to go to the beginning of that line) and:

Ctrl + x r t

Which is the command to insert at the rectangle you just specified (a rectangle of 0 width).

2008-8-21 6:45PM <enter>

Or whatever you want to prepend... then you will see that text prepended to every line within the 0 width rectangle.

UPDATE: I just realized you don't want the SAME date, so this won't work... though you may be able to do this in emacs with a slightly more complicated custom macro, but still, this kind of rectangle editing is pretty nice to know about...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top