9

While discussing over the differences between /usr/bin/time and the shell (bash and zsh) built-in time, someone mentioned that one can use \time as a shorthand to get /usr/bin/time.

First it seemed like a nice innocent shortcut, but then some questions came up:

  • Why does t\ime work too?
  • Why does \cd change the directory, even though /usr/bin/cd¹ does not?

So obviously, \foo is not equivalent to $(which foo). The question is now:

Is the observed behaviour of \foo in both bash and zsh in any way covered by the POSIX definition of a shell, and if so, why does it behave like it does?


Footnote 1: /usr/bin/cd is, on my system,

#!/bin/sh
builtin cd "$@"
14

t\ime or \cd (or "tim"e or 'cd' or ${-##*}time or ${-+time} and every other combination of quoting and expansions you could think of that would eventually resolve to time or cd), is that: another way to write cd and time.

However, that would eventually resolve to cd or time at a later time of the shell syntax parsing and interpretation. In particular, that happens long after shell keyword recognition and alias substitution take place.

So, at the time the shell is looking for keywords in its language, it is not recognising ti\me as the time shell keyword. So a:

ti\me echo test

would be recognised by the shell as a simple command as opposed to the time keyword followed by a simple command.

Then the quoting in ti\me would be processed (here that backslash is quoting the m character which doesn't need quoting anyway, the quoting character is removed, you get time) and a time command would be looked-up like any other commands (in the list of builtins, functions and executable files in $PATH. Most likely that will be /bin/time here)

For cd, there's no cd keyword in the shell language, just a cd builtin command (which takes precedence over your /usr/bin/cd). However, if you do define an alias for cd (like alias cd=pushd), same again. As alias substitution is done very early, before quote removal, if you have an alias for cd and not one for \cd (note that not many shells allow aliases with backslashes in them), then by writing:

\cd dir

you're making sure your cd alias is not substituted.

In short, quoting a command name or any part of it prevents it from being seen as a shell keyword (keywords being things like while, for, if, {... time is a keyword in some shells only), and bypasses an alias you may have for it.

It does not however force that command to resolve to an executable file in $PATH, the command is still searched first among functions (which you can work around by doing command time cmd...) and builtins (which you can work around by doing env time cmd..., though I don't know of a shell that has a builtin time command).

Note that quoting can also have an influence on the behaviour of the special builtins of the typeset/declare/export/local... family in some shells. See Are quotes needed for local variable assignment? for details.

  • So, the difference between time and cd which leads to the difference in observed behaviour is that time is a keyword and cd is a builtin command? – Jonas Schäfer Mar 15 '16 at 13:58
  • 1
    @JonasWielicki, it's that time is a keyword and that cd is not. (and if you had an alias for cd or time, that would be another matter). That cd is builtin or not has no incidence at this point (as far as the influence of quoting is concerned). Some shells however have a few builtins that are halfway between keywords and builtins as their parsing is done differently from other builtins. That's the case of export/typeset/declare. I should probably add some note about it in this answer. – Stéphane Chazelas Mar 15 '16 at 14:13

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.