It is usual to do time cmd for many types of cmd(s) in bash:

$ time true
real    0m0.000s
user    0m0.000s
sys     0m0.000s

The output format could be changed (even to a posix format with time -p):

$ TIMEFORMAT='real %R'; time true
real 0.000

But zsh doesn't report the time for simple commands (try also time echo):

% time true

Converting the command to a pipe reports other things:

$ zsh -c 'time echo yes | cat'
echo yes  0.00s user 0.00s system 26% cpu 0.001 total
cat  0.00s user 0.00s system 85% cpu 0.002 total

The shell could be forced to give a time output with a subshell (…):

$ zsh -c 'time ( true )'
( true; )  0.00s user 0.00s system 26% cpu 0.005 total

But that doesn't work with {…}, nor with builtins like for:

$ zsh -c 'time { for i in $(seq 100); do ls; done >/dev/null; }'

How could zsh's time made to accept simple commands without a subshell.

Or, an even simpler question:

Is there a way to write code that works in ksh, bash,zsh with the time keyword?


time does not time commands. From the Single Unix Specification's rationale:

The term utility is used, rather than command, to highlight the fact that shell compound commands, pipelines, special built-ins, and so on, cannot be used directly.

The SUS also states that the result of time on special built-in commands is undefined, and its results when used on anything other than a simple command (i.e. on pipelines or command groupings) are unspecified.

This is because time is not required to be special shell syntax, nor a built-in command. And whether it was varied quite significantly at the time of first standardization, and varies significantly now.

  • In the Almquist and (Heirloom) Bourne shells, time is neither reserved word nor built-in command. It is an external command, and so cannot be applied to anything other than a simple command. The external time command on the BSDs uses the process usage information returned from the kernel by the wait4() library function, and requires that the program being timed be a shell if you want to time shell built-in commands and pipelines. So things like time bindkey do not find a utility to execute and things like time echo time the operation of the external echo command and not a shell built-in one.
  • In the C shell, time is a built-in command, and cannot be applied to anything other than a simple command. time works by looking at the results of the wait4() library function, which necessitates a child process to wait for. So the C shell's time always forks a child process, even for otherwise built-in commands. You will find that things like time bindkey -v achieve nothing because they are run in a child process as a consequence of time.
  • In the Korn and Bourne Again shells, time is a reserved word in the shell syntax, and can be applied to pipelines. These shells do not use the child process usage information returned by the wait4() library function but calculate times by bracketing invocations of commands with calls to getrusage(), and doing subtractions.
  • In the Z shell, time is a reserved word in the shell syntax, and can be applied to pipelines. The Z shell does use the process usage information returned from the kernel by the wait4() library function, but does not force forking for built-in commands. So it reports nothing when no child process has been forked (as it the case for built-in commands such as true); but conversely the likes of time set -o vi actually achieve something.

As its rationale states, the Single Unix Specification is loosely worded in order to allow all of the various behaviours. And it nods in the direction of timing shell built-in commands being a problem.

  • The spec say: ... pipelines ... cannot be used directly. Both zsh and bash do apply that reserved word (not utility as defined in the spec) to pipelines, so they are both "out of spec" from my viewpoint. – Isaac Jan 18 '20 at 19:41
  • All built-in commands become timed when in a pipeline: Try zsh -c 'time true | read | true'. It reports time information for both true and read, but not for the last true. Shouldn't time { true } work? The command is encapsulated. – Isaac Jan 18 '20 at 19:50
  • I did put emphasis on "when no child process has been forked". A pipeline forks child processes. – JdeBP Jan 18 '20 at 20:22
  • I would like to know why all people seem to know the so called heirloom shell, that did get only attention for half a year and that is neither fully portable nor compatible to the historic Bourne Shell. If you like a portable shell that is 100% compatible to the Bourne Shell, rather use obosh, which is a compile variant of bosh. – schily Jan 18 '20 at 20:25

While most shells support to time external and builtin commands, zsh does not support timing for builtin commands.

If you need to get a time result, you may like to call

time /bin/true

or send a bug report to the zsh people.

With the new information things look different.

Timing complex commands only works in case that time is a reserved word in the shell.

So you have two limiting factors

  • the shell needs to be able to time builtin commands

  • the shell needs to implement time as a reserved word that enhances the syntax of the shell

This reduces the list of potential shell candidates to:

bosh bash mksh ksh

For builtin commands, the shell needs to know how to mesure its own timing.

For complex commands, the shell needs to implement time inside the interpreter.

  • The /bin/true has to be loaded, started, and then executed. That takes some set-up time which a builtin like true doesn't need nor use. The times reported would be inherently different. Try bash -c 'for cmd in true /bin/true; do time for((i=1;i<10**3;i++)); do $cmd; done; done' (local result: real 0.016 real 1.618 .... A factor of 100). – Isaac Jan 18 '20 at 19:08
  • You seem to want the timing and zsh. The other variant seems to be not to use zsh. – schily Jan 18 '20 at 19:39
  • No, @schily I am trying my best to be shell agnostic in this question. I do prefer bash, but I also need to measure timing of commands in zsh. So, the question remains: How to time a for loop in zsh? – Isaac Jan 18 '20 at 19:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.