6

I have been delving into bash for the first time and want to try to test some code to compare different ways of achieving the same end. As part of this I have come across the time and times methods of recording the runtime of the code. For a simple one line script created via:

echo "echo a script" > script

I get:

$ time bash ./script
a script

real    0m0.009s
user    0m0.006s
sys 0m0.002s

$ times bash ./script
0m0.082s 0m0.074s
0m0.019s 0m0.041s

$ /usr/bin/time bash ./script
a script
0.00user 0.00system 0:00.00elapsed 80%CPU (0avgtext+0avgdata 3328maxresident)k
0inputs+0outputs (0major+148minor)pagefaults 0swaps
$ type -a time
time is a shell keyword
time is /usr/bin/time
time is /bin/time
$ type -a times
times is a shell builtin

$ which -a time
/usr/bin/time
/bin/time

bash -c help takes me to:

$ help time
time: time [-p] pipeline  
    Report time consumed by pipeline's execution.

$ help times
times: times  
    Display process times.

And man time gives me:

TIME(1)..........General Commands Manual..........TIME(1)

NAME time - run programs and summarize system resource usage

Users of the bash shell need to use an explicit path in order to run the external time command and not the shell builtin variant. On system where time is installed in /usr/bin, the first example would become /usr/bin/time wc /etc/hosts

The bash reference manual describes time as a reserved word that has, "special meaning to the shell. They are used to begin and end the shell’s compound commands", whereas times is described as a shell builtin command, "inherited from the Bourne Shell. These commands are implemented as specified by the POSIX standard".

Apart from a line in the manual saying:

The use of time as a reserved word permits the timing of shell builtins, shell functions, and pipelines. An external time command cannot time these easily.

I can't see the reasoning for three very similar commands.

Which one should I use to test different approaches and optimise my scripts?

1 Answer 1

7

times (built-in)

times - as per help times:

Prints the accumulated user and system times for the shell and all of its child processes.

Emphasis on "accumulated" and on "for the shell and all of its child processes". It doesn't take any argument, and it doesn't measure the time of execution of another command: It prints the current user and system time spent by the shell and its children for their own execution.

For example, if I wanted to printf an empty string a million times, the time it would take a shell to run all those commands would be significant (focus on the first field of the commented lines):

> times; for x in {1..1000000}; do printf ''; done; times
# running printf a million times in the current shell
0m0,021s 0m0,000s # shell's user time is about 0
0m0,009s 0m0,003s
0m2,232s 0m0,087s # shell's user time increased by about 2 seconds
0m0,009s 0m0,003s
> times; (for x in {1..1000000}; do printf ''; done); times
# running printf a million times in a subshell
0m2,239s 0m0,090s
0m0,009s 0m0,009s # shell's children user time is about 0
0m2,239s 0m0,096s
0m2,308s 0m0,153s # shell's children user time increased by about 2 seconds

Which gives it a completely different purpose from time (reserved word) and /usr/bin/time (executable). Most of the time (pun not intended), in scripts, you'll use time and /usr/bin/time.

time (reserved word) / /usr/bin/time (executable)

As @terdon crucially notes, a time "utility" that's implemented in such a way that "can be accessed via the exec family of functions" must be present on a system to be POSIX-compliant1; this, alone, justifies the presence of /usr/bin/time in addition to time.

The most significant differences between the reserved word and the executable are:

  • The first is a shell facility. Which means you'll always be able to use it in Bash (and I guess in most shells), while you won't necessarily be able to use the second on a non-POSIX-compliant system; conversely, if you're running a shell that doesn't have the first, depending on the system and its POSIX compliance, you may still be able to use the second. Realistically speaking, I've personally never used a distro that didn't have either Bash or /usr/bin/time. Also note that, in general, built-in often run faster than external executables.
  • The first may be applied to built-ins, functions, lists and subshells; the second may not.
time printf ''
function foo() {}; time foo
time { foo; bar; }
time (foo)

So in practice, on Ubuntu at least, as far as a single command is concerned, the difference between the two mainly boils down to the format in which the output is printed.

Using the reserved word you have little output customization available (basically you can print using the default format and a POSIX-compliant format), while using the executable you have way more options available (see man time).

> time sleep 5; printf '\n'; /usr/bin/time sleep 5

real    0m5,002s
user    0m0,001s
sys     0m0,000s

0.00user 0.00system 0:05.00elapsed 0%CPU (0avgtext+0avgdata 2176maxresident)k
0inputs+0outputs (0major+95minor)pagefaults 0swaps

  1. From the link:

Any of the standard utilities may be implemented as regular built-in utilities within the command language interpreter. This is usually done to increase the performance of frequently used utilities or to achieve functionality that would be more difficult in a separate environment. [...] However, all of the standard utilities, including the regular built-ins in the table, but not the special built-ins described in Special Built-In Utilities, shall be implemented in a manner so that they can be accessed via the exec family of functions as defined in the System Interfaces volume of POSIX.1-2008 and can be invoked directly by those standard utilities that require it (env, find, nice, nohup, time, xargs).

7
  • ah-ha: re. times accumulation (my old laptop is showing its age) run1 0m0.082s 0m0.107s 0m0.034s 0m0.044s 0m8.970s 0m0.769s 0m0.034s 0m0.044s run2 0m9.186s 0m0.773s 0m0.034s 0m0.044s 0m17.987s 0m0.784s 0m0.034s 0m0.044s run3 0m17.988s 0m0.784s 0m0.034s 0m0.044s 0m26.942s 0m0.793s 0m0.034s 0m0.044s So times from the command line is just showing me the time the bash shell has been doing stuff....
    – dmkonlinux
    Commented May 29 at 15:26
  • @dmkonlinux I initially failed to mention another very important difference, see the updated answer: you'll need time (reserved word) each time you want to measure the execution time of basically anything other than a single command
    – kos
    Commented May 29 at 15:26
  • 1
    Having a time executable is POSIX mandated, that's why you find the executable even on systems that ship with shells with a builtin time command. Same as /usr/bin/test or /usr/bin/[ which both exist as binaries despite almost always being overridden by the equivalent shell builtins.
    – terdon
    Commented May 29 at 19:51
  • 1
    This answer gets better and better. Can I suggest adding "Any of the standard utilities may be implemented as regular built-in utilities within the command language interpreter. This is usually done to increase the performance of frequently used utilities or to achieve functionality that would be more difficult in a separate environment." from the posix link as it underlines why you might add a shell builtin.
    – dmkonlinux
    Commented May 30 at 2:35
  • 1
    @dmkonlinux Makes sense, thanks, I added that bit, although I wasn't a fan of that quote in the middle of the answer before either, so with it becoming increasingly long I decided to put it at the end as footnote (and briefly mentioned that built-ins usually run faster in-context), as I feel like otherwise it would distract too much from the comparison
    – kos
    Commented May 30 at 4:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .