How to measure time of program execution and store that inside a variable

To get the output of time into a var use the following:

usr@srv $ mytime="$(time ( ls ) 2>&1 1>/dev/null )"
usr@srv $ echo "$mytime"

real    0m0.006s
user    0m0.001s
sys     0m0.005s

You can also just ask for a single time type, e.g. utime:

usr@srv $ utime="$( TIMEFORMAT='%lU';time ( ls ) 2>&1 1>/dev/null )"
usr@srv $ echo "$utime"
0m0.000s

To get the time you can also use date +%s.%N, so take it before and after execution and calculate the diff:

START=$(date +%s.%N)
command
END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
# echo $DIFF

In bash, the output of the time construct goes to its standard error, and you can redirect the standard error of the pipeline it affects. So let's start with a command that writes to its output and error streamas: sh -c 'echo out; echo 1>&2 err'. In order not to mix up the command's error stream with the output from time, we can temporarily divert the command's error stream to a different file descriptor:

{ time -p sh -c 'echo out; echo 1>&2 err' 2>&3; }

This writes out to fd 1, err to fd 3, and the times to fd 2:

{ time -p sh -c 'echo out; echo 1>&2 err' 2>&3; } \
    3> >(sed 's/^/ERR:/') 2> >(sed 's/^/TIME:/') > >(sed 's/^/OUT:/')

It would be more pleasant to have err on fd 2 and the times on fd 3, so we swap them, which is cumbersome because there's no direct way to swap two file descriptors:

{ { { time -p sh -c 'echo out; echo 1>&2 err' 2>&3; } 3>&2 2>&4; } 4>&3; } 3> >(sed 's/^/TIME:/') 2> >(sed 's/^/ERR:/') > >(sed 's/^/OUT:/')

This shows how you can postprocess the output of the command, but if you want to capture both the output of the command and its times, you need to work harder. Using a temporary file is one solution. In fact, it's the only reliable solution if you need to capture both the command's standard error and its standard output. But otherwise, you can capture the whole output and take advantage of the fact that time has a predictable format (if you use time -p to get the POSIX format or the bash-specific TIMEFORMAT variable).

nl=$'\n'
output=$(TIMEFORMAT='%R %U %S %P'; mycommand)
set ${output##*$nl}; real_time=$1 user_time=$2 system_time=$3 cpu_percent=$4
output=${output%$nl*}

If you only care about wall clock time, running date before and after is a simple solution (if slightly more imprecise due to the extra time spent loading the external command).


If you are in bash (and not sh) and you DO NOT need sub-second accuracy, you can skip the call to date entirely and do it without spawning any extra processes, without having to separate the combined output, and without having to capture and parse output from any commands:

# SECONDS is a bash special variable that returns the seconds since set.
SECONDS=0
mycmd <infile >outfile 2>errfile
DURATION_IN_SECONDS=$SECONDS
# Now `$DURATION_IN_SECONDS` is the number of seconds.