try this, it runs a simple command with arguments and puts the times $real $user $sys and preserves the exit code. It
It also does not fork subshells or trample on any variables except real user sys, and does not otherwise interfere with the running of the script
timer () {
{ time { "$@" ; } 2>${_} {_}>&- ; } {_}>&2 2>"/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
set -- $?
read -d "" _ real _ user _ sys _ < "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
rm -f "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
return $1
}
e.g.
timer find /bin /sbin /usr rm /tmp/ | grep '.sh$'
echo $real $user $sys
note: it only times the simple command, not the entirea pipeline, whose components are run in a subshell
This version allows you to specify as $1 the name of the variables that should receive the 3 times:
timer () {
{ time { "${@:4}" ; } 2>${_} {_}>&- ; } {_}>&2 2>"/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
set -- $? "$@"
read -d "" _ "$2" _ "$3" _ "$4" _ < "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
rm -f "/tmp/$$.$BASHPID.${#FUNCNAME[@]}"
return $1
}
e.g.
timer r u s find /bin /sbin /usr rm /tmp/ | grep '.sh$'
echo $r $u $s
and may be useful if it ends up being called recursively, to avoid trampling on times; but then r u s etc should be declared local in their use.
http://blog.sam.liddicott.com/2016/01/timeing-bash-commands.html