Search code examples
bashsh

Get both duration time of a command and the command result


I am measuring the command duration by the tool time, but the result of the command is hidden. For example I am measuring the duration of find or ls and I see the duration, but not a list of files.

v=&&X=$((time v=$(ls)) 2>&1 | grep real)&&echo $X&&echo "$v"
u@debian:~$ v=&&X=$((time v=$(ls)) 2>&1 | grep real)&&echo $X&&echo "$v"
real 0m0.004s

u@debian:~$

I would like both X and v variables be reachable. X schould return real 0m0.004s and v schould return a list of files.

How to measure the duration of a command and get the result of the command?


Solution

  • This Shellcheck-clean Bash code demonstrates one way to do what you want:

    #! /bin/bash -p
    
    ls_time=$({ time ls; } 2>&1)
    ls_output=${ls_time%$'\n'real*}
    time_output=${ls_time:${#ls_output}+1}
    
    X=${time_output%%$'\n'*}
    v=${ls_output%$'\n'}
    
    declare -p X v
    
    • ls_time=$({ time ls; } 2>&1) captures the entire output (both standard output and standard error) of time ls into the variable ls_time.
    • ls_output=${ls_time%$'\n'real*} sets ls_output to the full output of ls. It does that by removing the shortest string at the end of $ls_time that begins with a newline followed by the string real. See Removing part of a string (BashFAQ/100 (How do I do string manipulation in bash?)) for an explanation of ${ls_time%...}.
    • time_output=${ls_time:${#ls_output}+1} puts the timing output lines from time ls (excluding the leading newline) into time_output. See Extracting parts of strings (BashFAQ/100 (How do I do string manipulation in bash?)) for an explanation of ${ls_time:...}.
    • X=${time_output%%$'\n'*} sets X to the timing output lines from time ls (excluding the leading newline) with everything after the first newline (the newline at the end of the real ... line) removed.
    • v=${ls_output%$'\n'} sets v to the output of ls with the final newline (if any (the output could be empty)) removed. That makes it equivalent to v=$(ls).
    • declare -p X v outputs the values of the X and v variables in a safe and unambiguous way. echo $var is not safe. echo "$var" is better, but still not fully safe. See the accepted, and excellent, answer to Why is printf better than echo?. printf '%s\n' "$var" is safe, but can be ambiguous if $var contains newline characters.