I am preparing some code for a another blog post I came across some very unexpected behavior on my terminal that really got me thinking 🤔. Time was behaving in 2 different ways depending on what it seems an entirely unrelated reason.
Check this output out:
$ time go run github.com/efrag/blog-posts/go_routines/ one-routine-wait ... real 0m1.556s user 0m1.545s sys 0m0.064s
Looks pretty normal right? I run the command prefixed with
time and I got the expected output. But check what happens when I run it like this:
$ GOMAXPROCS=10 time go run github.com/efrag/blog-posts/go_routines/ one-routine-wait ... 1.54user 0.07system 0:01.58elapsed 102%CPU (0avgtext+0avgdata 46812maxresident)k 0inputs+3112outputs (0major+16202minor)pagefaults 0swaps
That looks pretty weird right? Did my terminal suddenly decide that I am an “advanced” user and went all out with a more precise/detailed view of the output for
time? Surely that can’t be the case 🤪 – so what’s going on here?
I decided to strip out all the things and just go with a very plain command to eliminate any doubt. Let’s just use a simple
ls on a directory and run things again:
$ time ls -l ... real 0m0.005s user 0m0.005s sys 0m0.000s
and one more time with:
$ a=1 time ls -l ... 0.00user 0.00system 0:00.00elapsed 75%CPU (0avgtext+0avgdata 3032maxresident)k 0inputs+0outputs (0major+162minor)pagefaults 0swaps
Again same output but now it got me thinking – could this be something related with my terminal instead? Well, kinda. After a lot of looking around and reading the
man pages for both
time it turns out that there is a logical explanation after all ¯\_(ツ)_/¯.
Bash offers extended functionality to the terminal. When in doubt if something is actually part of
bash or a standard unix command you can do the following:
$ type which which is /usr/bin/which $ type time time is a shell keyword
Turns out when running
time on the terminal I was not using the Unix
time command rather the
time keyword from
Looking further in the
bash documentation there is a section that talks about pipelines in
bash and the example there demonstrates the use of the keyword
A pipeline is a sequence of one or more commands separated by one of the control operators | or |&. The format for a pipeline is:
[time [-p]] [ ! ] command [ [|⎪|&] command2 … ]
If the time reserved word precedes a pipeline, the elapsed as well as user and system time consumed by its execution are reported when the pipeline terminates.
man page for the unix
time command actually verifies this as well as it says:
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.
OK – so now that we have all of clues what is actually happening with my command? Turns out that the explanation is quite simple. Bash will use the builtin variant when we define a pipeline that starts with the keyword
time which follows the
POSIX standard of reporting the time statistics.
But, when we put anything before the keyword
time then bash will not default to its builtin keyword but rather use the external unix command whose output format is determined as
%Uuser %Ssystem %Eelapsed %PCPU (%Xtext+%Ddata %Mmax)k %Iinputs+%Ooutputs (%Fmajor+%Rminor)pagefaults %Wswaps
which is what I was seeing when defining an
env variable before running my command 🤯.