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

  • In order to find out how long certain operations within a Bash (v4+) script take, I would like to parse the output from the time command "separately" and (ultimately) capture it within a Bash variable (let VARNAME=...).

    Now, I am using time -f '%e' ... (or rather command time -f '%e' ... because of the Bash built-in), but since I already redirect the output of the executed command I'm really lost as to how I would go about to capture the output of the time command. Basically the problem here is to separate the output of time from the output of the executed command(s).

    What I want is the functionality of counting the amount of time in seconds (integers) between starting a command and its completion. It doesn't have to be the time command or the respective built-in.


    Edit: given the two useful answers below, I wanted to add two clarifications.

    1. I do not want to throw away the output of the executed command, but it will not really matter whether it ends up on stdout or stderr.
    2. I would prefer a direct approach over an indirect one (i.e. catching output directly as opposed to store it in intermediate files).

    The solution using date so far comes closes to what I want.

    The most direct way to get the data and handle it while still letting it run normally would be to do it in a C program using `fork()`, `execvp()` and `wait3()/wait4()`. This is ultimately what time and friends are doing. I'm not aware of a simle way to do it in bash/perl without redirecting to a file or similar approach.

    There is a related question that you might find interesting going on here.

  • binfalse

    binfalse Correct answer

    10 years ago

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

    [email protected] $ mytime="$(time ( ls ) 2>&1 1>/dev/null )"
    [email protected] $ echo "$mytime"
    
    real    0m0.006s
    user    0m0.001s
    sys     0m0.005s
    

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

    [email protected] $ utime="$( TIMEFORMAT='%lU';time ( ls ) 2>&1 1>/dev/null )"
    [email protected] $ 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
    

    I didn't want to throw away the output from the command though. So I guess your third code block is closest to what I had in mind. Although I'd write the last one as `DIFF=$((END-START))`, making use of the arithmetic expressions. :) ... thanks for the answer. +1

    @STATUS_ACCESS_DENIED: Bash doesn't do floating point arithmetic, so if you want better than second resolution (`.%N` in binfalse's code), you either need `bc` or fancier calculations.

    @Gilles: I know. As I wrote in my question integers are fine. No need to have a higher resolution than second. But thanks, the date invocation would have to be changed. I had realized that, though.

    FYI, the date formatting %N doesn't seem to work on Mac OS X, it just returns "N". Ok on Ubuntu.

    Note that while the `time (cmd) 2> something` works at redirecting the timing output to `file`, it's not meant to (as per documentation), doesn't in other shells where `time` is a keyword and could be considered as a bug. I wouldn't rely on it as it may not work in future versions of `bash`.

    If you find yourself in a situation where there's `dc` but no `bc` (probably rare but I just did), you can use `DIFF=$(echo "$END $START - p" | dc)`.

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM

Tags used