The accepted solution using time
writes to stderr
.
The solution using times
writes to stdout
.
The solutions using $SECONDS
are missing sub-second precision.
The other solutions involve calling external programs like date
or perf
which is not efficient.
If you are fine with any of these, use it.
But if you need an efficient solution to get the times with millisecond precision and need them into variables such that the original output remains undisturbed you may combine process substitution with some redirections around time
which is much faster than calling external programs and allows redirections around the timing wrapper script as on the original command/script.
# Preparations:
Cmd=vgs # example of a program to be timed which is writing to stdout and stderr
Cmd="eval { echo stdout; echo stderr >&2; sleep 0.1; }" # other example; replace with your own
TIMEFORMAT="%3R %3U %3S" # make time output easy to parse
Select one of the following variants parsing the output of time
appropriate to you needs:
Shortest variant where stdout
of $Cmd
is written to stderr
and nothing to stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Longer variant that keeps original stdout
and stderr
separate of each other:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
Most complicated variant includes closing the extra file descriptors such that $Cmd
is called as if without this timing wrapper around it and lvm
commands like vgs
do not complain about leaked file descriptors:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
You can even fake a floating point addition in bash
without calling bc
which would be much slower:
CPU=`printf %04d $((10#${User/.}+10#${System/.}))` # replace with your own postprocessing
echo CPU ${CPU::-3}.${CPU: -3} s, Elapsed $Elapsed s >&2 # redirected independent of $Cmd
Possible outputs with the two examples of $Cmd
on a slow CPU:
File descriptor 3 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash
File descriptor 4 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash
VG #PV #LV #SN Attr VSize VFree
b3 3 24 0 wz--n- 1.31t 1.19t
CPU 0.052 s, Elapsed 0.056 s
Or:
stdout
stderr
CPU 0.008 s, Elapsed 0.109 s