In Bash, time
is a built-in reserved word you can prepend to a pipeline to measure the duration of executed commands. It implements a subset of features of the original time
binary, but does not involve shelling-out.
time
built-in will output the measurements to STDERR. Under some circumstances (time
is used to measure a failing function executed in a subshell with errexit enabled), the STDERR of time
will leak into the executed command.
Example:
Let’s define a couple of functions first
$ failing_fn () { false; }
$ successful_fn () { true; }
The following will result in measurements written into testfile
(while it shouldn’t, redirect happens in the subshell)
$ time (set -e; failing_fn 2>./testfile)
$ cat testfile
real 0m0.000s
user 0m0.000s
sys 0m0.000s
This does not happen if the subshell command is not a function
$ time (set -e; false 2>./testfile)
real 0m0.000s
user 0m0.000s
sys 0m0.000s
$ cat testfile
it also doesn’t happen when the failing function does not fail the pipeline (errexit is not enabled)
$ time (set +e; failing_fn 2>./testfile)
real 0m0.000s
user 0m0.000s
sys 0m0.000s
$ cat testfile
or if the function is successful
$ time (set -e; successful_fn 2>./testfile)
real 0m0.000s
user 0m0.000s
sys 0m0.000s
$ cat testfile
or when we do not use time with the subshell syntax directly
$ time eval '(set -e; failing_fn 2>./testfile)'
real 0m0.001s
user 0m0.001s
sys 0m0.000s
$ cat testfile
Oddly enough, simply adding | cat
to the pipeline inside the subshell will result in measurements output being duplicated into both STDERR of the current shell and STDERR of the subshell function
$ time (set -e; failing_fn 2>./testfile | cat)
real 0m0.001s
user 0m0.001s
sys 0m0.001s
$ cat testfile
real 0m0.001s
user 0m0.000s
sys 0m0.000s
and it works properly in case | cat
and eval
are present in the subshell (found this one by trial-and-error)
$ time (set -e; eval failing_fn 2>./testfile | cat)
real 0m0.001s
user 0m0.001s
sys 0m0.001s
$ cat testfile