3

I'm looking to capture the output of a shell script execution in real time to enrich it with information giving the date and time.

To illustrate, I have for example a script of this type that I must not modify:

#!/bin/bash
for i in 2 3 1
do
  echo "Waiting for $i seconds ..."
  sleep $i
done

The script produces the following output:

Waiting for 2 seconds ...
Waiting for 3 seconds ...
Waiting for 1 seconds ...

I am trying to produce the output of the type:

2021-06-16 11:44:48 [INFO] Waiting for 2 seconds ...
2021-06-16 11:44:50 [INFO] Waiting for 3 seconds ...
2021-06-16 11:44:53 [INFO] Waiting for 1 seconds ...

I use the following shell functions for formatting in a script that runs my initial script:

function log {
   echo `date +%Y-%m-%d" "%H:%M:%S`" $@"
   if [ "$LOGFILE" != "" ]
   then
      echo `date +%Y-%m-%d" "%H:%M:%S`" $@" >>$LOGFILE
   fi
}

function loginf {
   log "[INFO] $@"
}

I manage very well with a while loop on a read to capture the output of my script, but I get all the lines at the same time (end of its execution) and therefore all lines have the same datetime. I try to get the lines each time the script produces a line and not at the end of the execution.

pLumo
  • 26,204
  • 2
  • 57
  • 87
Thomas W
  • 31
  • 1
  • How do you call your initital script? This works well for me : `./script1.sh | while IFS= read -r l; do loginf "$l"; done`. See also https://serverfault.com/questions/72744/command-to-prepend-string-to-each-line – pLumo Jun 16 '21 at 13:41
  • 1
    `./script.sh | ts "%Y-%m-%d %H:%M:%S [INFO]"` –  Jun 16 '21 at 13:57
  • I created a script that contains your two functions and then the following code: `while { read; } do loginf $REPLY; done`. Running `./script1 | ./script2` (where `script1` is your first script and `script2` the above mentioned script) gives correct output for me, ie. different timestamps. – raj Jun 16 '21 at 13:58
  • don't need to use `echo` really, could just do `f(){ date "+%Y-%m-%d %H:%M:%S [INFO] $*"; }; f one two three` –  Jun 16 '21 at 14:08
  • `f(){ printf '%(%Y-%m-%d %H:%M:%S)T [%s] %s\n' -1 INFO "$*"; }; f one two three` even better... –  Jun 16 '21 at 14:10

2 Answers2

2

The ts command from package moreutils does precisely what you are looking for:

./script.sh | ts

It has various options for formatting the time stamp. For instance,

ts '%F %T [INFO]'

will give you the exact format you use in your question.

zwets
  • 11,795
  • 2
  • 32
  • 44
0

You can either use ts:

./your_script.sh | ts

Of, if you need something portable that works on systems where ts is not installed, you can do that in a simple while loop using the built-in read command:

./your_script.sh | while read line; do echo "$(date +'%Y-%m-%d %H:%M:%S') [INFO] $line"; done
vog
  • 131
  • 2