2

For example, suppose I have the script:

(echo a; sleep 1; echo b; sleep 3; echo c; sleep 2)

which outputs:

a
b
c

When running that script, possibly through a pipe, I would like to obtain something like:

1.00 a
3.00 b
2.00 c

because the line a was the last line of stdout for 1.00 seconds, before it was replaced by b as the last line.

I don't want to modify the program being run, and in my actual use case the stdout will be generated by a complex executable which I don't want to modify, e.g. QEMU booting the Linux kernel.

This would allow me to do a quick and dirty profiling of the program being run, to determine what segment is taking the longest.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985

2 Answers2

4

If you're happy with a resolution of seconds, you can use this one-liner:

t=$SECONDS; (echo a; sleep 1; echo b; sleep 3; echo c; sleep 2) | while read line; do echo $((SECONDS - t)) $line; t=$SECONDS; done

If you are OK with installing node.js, this is exactly what gnomon does:

enter image description here

chthonicdaemon
  • 19,180
  • 2
  • 52
  • 66
3

moreutils ts

I knew someone had written this before!

$ sudo apt-get install moreutils
$ (echo a; sleep 1; echo b; sleep 3; echo c; sleep 2; echo d; sleep 1) | ts -i
00:00:00 a
00:00:01 b
00:00:03 c
00:00:02 d
$ (echo a; sleep 1; echo b; sleep 3; echo c; sleep 2; echo d; sleep 1) | ts -i '%.s'
0.000010 a
0.983308 b
3.001129 c
2.001120 d
$ (echo a; sleep 1; echo b; sleep 3; echo c; sleep 2; echo d; sleep 1) | ts -s
00:00:00 a
00:00:01 b
00:00:04 c
00:00:06 d   
$ (echo a; sleep 1; echo b; sleep 3; echo c; sleep 2; echo d; sleep 1) | ts
Apr 13 03:10:44 a
Apr 13 03:10:45 b
Apr 13 03:10:48 c
Apr 13 03:10:50 d

If you Google instead for the related "add timestamp to stdout" there are many results:

Bash while read

This gives it in millis:

stdouttime() (
  tp="$(date +%s%N)"
  while read line; do
    tc="$(date +%s%N)"
    echo $(((tc - tp) / 1000000))
    echo "$line"
    tp=$tc
  done
  tc="$(date +%s%N)";
  echo $(((tc - tp) / 1000000))
)
(echo a; sleep 1; echo b; sleep 3; echo c; sleep 2) | stdouttime

Sample output:

2
a
1000
b
3002
c
2002

Based on: https://serverfault.com/questions/151109/how-do-i-get-current-unix-time-in-milliseconds-using-bash

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • 1
    Good use of bash, without resorting to outside programs. Rather than tp and tc, which have no meaning, if you need to modify the script 2yrs from now, I would use 'begin' and 'end'. Additionally, I would append " millisecons" or " ms" to the output, to add context. Thanks for the reference to the other question. – xizdaqrian Apr 12 '18 at 23:58