0

Bash Reference Manual says

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.

  1. But it only compares reserved word time and external command time, and doesn't address the question:

    Why does Bash implement time as a reserved word, instead of a builtin command?

    What advantages can that give?

  2. What are other reserved words which can also be implemented as (builtin or external) commands? What are their advantages over their command counterparts? (Trying to figure out if their advantages are shared or specific to each of them)

    For example,

    • the reserved word [[...]] versus the builtin command test or [
    • the reserved word select versus the builtin command read
Tim
  • 101,790

2 Answers2

8

The text you quote already explains why time is a keyword:

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.

If time was only a builtin, it wouldn't be able to properly measure the time taken by a pipeline, e.g.:

$ time sleep 2 | sleep 4

real    0m4.002s
user    0m0.000s
sys     0m0.002s

Here time returned 4 seconds which is the time taken by the whole pipeline. If implemented as a builtin, the shell grammar would only allow it to it return 2 seconds because a command, whether builtin or not, is only seeing its parameters, in that specific case, sleep 2.

Other keywords that cannot be implemented by builtins are the ones used for structured constructions like for, while, until, case, do, done, select, if, then, else, function. Like time, they need to be able to process the lines to be interpreted without being restricted to a simple command boundary.

It is for the same reason, i.e. the ability to access to the whole shell input to be parsed and not just a command and its parameters that these keywords are implement as is. For example the [ command parameters are subject to shell expansion and processing so you cannot reliably use * in a test and > would be taken as a redirection with unexpected results.

On the other hand, [[ is changing the shell behavior so you can use whatever syntax it accepts without being bothered by the shell.

Here are some examples showing the difference in behavior:

$ if [ * = "*" ]; then echo ok; fi
bash: [: too many arguments
$ if [[ * = "*" ]]; then echo ok; fi
ok

$ if [ 1 > 2 ]; then echo unexpected ; else echo expected; fi
unexpected
$ if [ 1 -gt 2 ]; then echo unexpected ; else echo expected; fi
expected
$ if [[ 1 > 2 ]]; then echo unexpected ; else echo expected; fi
expected

Note that not only does if [ 1 > 2 ] return an unexpected result but it also creates (or overwrite!) in the current directory a file named 2.

jlliagre
  • 61,204
  • Thanks. (1) If implemented as a builtin, why can't time time a pipeline, per the shell grammar? (2) What about the reserved word [[...]] versus the builtin command test or [, and the reserved word select versus the builtin command read? Do they also share the same thing as reserved word time versus hypothetical builtin time? – Tim Mar 18 '16 at 08:37
  • (1) Because a command can only see its parameters, in that case "sleep 2", so a builtin based time would be unable to be aware of what is on the other side of the pipeline, and even that there is a pipeline in the first place. (2) [[ is able to change the behavior of the shell, for example by preventing * to be expanded, a builtin, like an external command, cannot do that. select span to a do,done block which would be invisible to a builtin. – jlliagre Mar 18 '16 at 08:51
  • Most of the previous comment added to my reply. – jlliagre Mar 18 '16 at 13:43
1

An important reason for time being a reserved word in bash is that this is a copy of a concept from ksh.

ksh of course likes to permit time to do more than an external command or a builtin could do and likes to do timing for a while pipeline.

BTW: The fact that time is a reserved word in ksh would be a POSIX compliance bug, but parser from ksh checks whether the next word starts with a - and in such a case just calls the external command /usr/bin/time. Given that POSIX requires you to call time -p command for POSIX compliance, the whole behavior from ksh is POSIXcompliant.

BTW: [[ is a reserved word in ksh to make [[ ... ]] part of the shell syntax. This avoids the need to use shell escapes (similar to the case construct) for patterns and it allows the operators > and < to be used as arithmetic operators instead of being recognized as I/O redirections.

schily
  • 19,173
  • Thanks.About [[...]], (1) What do you mean by "This avoids the need to use shell escapes (similar to the case construct) for patterns"? What is "shell escapes", and how is it for the case construct? (2) "it allows the operators > and < to be used as arithmetic operators". Within [[...]], aren't > and < just normal characters, forming part of the string or pattern? Do you mean they are not part of the string or pattern, but arithmetic operators? – Tim Mar 19 '16 at 03:16
  • < and > redirect in/output for a normal command like test even when it id called as [ and shell escaping is using backslashes or single quotes. – schily Mar 21 '16 at 09:56