35

How can I make bash use time binary (/usr/bin/time) by default instead of the shell keyword?

which time returns /usr/bin/time
type time returns time is a shell keyword
Running time is obviously executing the shell keyword:

$ time

real    0m0.000s
user    0m0.000s
sys     0m0.000s
$ /usr/bin/time
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
   [--portability] [--format=format] [--output=file] [--version]
   [--quiet] [--help] command [arg...]

enable -n time returns bash: enable: time: not a shell builtin

5 Answers5

39

You can use the command shell built-in to bypass the normal lookup process and run the given command as an external command regardless of any other possibilities (shell built-ins, aliases, etc.). This is often done in scripts which need to be portable across systems, although probably more commonly using the shorthand \ (as in \rm rather than command rm or rm, as especially the latter may be aliased to something not known like rm -i).

$ time

real    0m0.000s
user    0m0.000s
sys 0m0.000s
$ command time
Usage: time [-apvV] [-f format] [-o file] [--append] [--verbose]
       [--portability] [--format=format] [--output=file] [--version]
       [--quiet] [--help] command [arg...]
$ 

This can be used with an alias, like so:

$ alias time='command time'
$ time
Usage: time [-apvV] [-f format] [-o file] [--append] [--verbose]
       [--portability] [--format=format] [--output=file] [--version]
       [--quiet] [--help] command [arg...]
$ 

The advantage of this over e.g. alias time=/usr/bin/time is that you aren't specifying the full path to the time binary, but instead falling back to the usual path search mechanism.

The alias command itself can go into e.g. ~/.bashrc or /etc/bash.bashrc (the latter is global for all users on the system).

For the opposite case (forcing use of the shell built-in in case there's an alias defined), you'd use something like builtin time, which again overrides the usual search process and runs the named shell built-in. The bash man page mentions that this is often used in order to provide custom cd functionality with a function named cd, which in turn uses the builtin cd to do the real thing.

user
  • 28,901
  • You can also inquire where a particular command is coming from using the command type -a <cmd>. – slm Aug 10 '13 at 18:29
  • 15
    command doesn't bypass builtins (except in zsh when not emulating other shells). It bypasses functions and that's the main reason for its existence. Its second role is to remove the special in special builtins. It bypasses aliases and keywords only because those are only expanded in first position (in zsh for instance, it doesn't bypass global aliases). There is no time bash builtin. time is a keyword so you can do for instance time { foo; bar; }. – Stéphane Chazelas Aug 10 '13 at 21:14
  • 1
    @StephaneChazelas By all means feel free to edit that into the answer to provide a more accurate description. command works in this particular case, as exemplified, but obviously a correct answer is better than a half-right one. – user Aug 11 '13 at 10:44
  • 2
    The last part of your answer is wrong. time is not a shell builtin, but rather a shell keyword. builtin time doesn't work. – admirabilis May 18 '15 at 23:40
  • similar to command would be to just quote it: 'time' echo test – mxmlnkn May 17 '16 at 00:04
11

There is a shortcut in bash to sidestep keywords, without having to specify a path or use another builtin like command: Escape it with a backslash.

=^_^= izkata@Izein:~$ time

real    0m0.000s
user    0m0.000s
sys     0m0.000s
=^_^= izkata@Izein:~$ \time
Usage: time [-apvV] [-f format] [-o file] [--append] [--verbose]
       [--portability] [--format=format] [--output=file] [--version]
       [--quiet] [--help] command [arg...]

Personally, I find this more readable and safer, as this is possible:

=^_^= izkata@Izein:~$ alias command=echo
=^_^= izkata@Izein:~$ command time
time
Izkata
  • 709
5

The general solutions for built-ins (for example test) are [1]:

  • use env (all shells)

    $ env test
    external test
    
  • disable the builtin (only bash and zsh):

    $ test 1 = 1 && echo "yes"
    yes
    $ enable -n test        ### for bash. Re-enable with "enable test".
    $ disable test          ### for zsh. Re-enable with "enable test".
    $ test
    external test
    
  • use any slash / to call the command (all shells):

    $ test 1 = 1 && echo "yes"
    yes 
    $ ~/bin/test
    external test
    
  • make an alias (fails inside a bash script, except if shopt -s expand_aliases is used):

    $ alias test='~/bin/test'             ### remove with 'unalias test'.
    $ test
    external test
    

But time is not a builtin.

The word time is a "Reserved word", not a command and neither a built-in. That enable this solutions:

  • Quote the word. This does not work with built-ins.
    Many forms of quoting work: \time "time" 'time' ti\me ti"me", etc.

    $  time
    
    real    0m0.000s
    user    0m0.000s
    sys     0m0.000s
    
    $ \time
    Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
           [--portability] [--format=format] [--output=file] [--version]
           [--quiet] [--help] command [arg...]
    

    This is useful to bypass an alias. Even if test is aliased, \test will execute the PATHed command (or the builtin if it has not been disabled).

  • Use the builtin command (this does not work with built-ins):

    $ command time
    
  • As above for built-ins, using any slash / works:

    $ /usr/bin/time
    
  • As above for built-ins, an alias also work here:

    $ alias time='command time'
    $ alias time='/usr/bin/time'
    

[1] Lets assume there is an external executable in ~/bin/test that prints "external test". And further: lets assume that ~/bin is ahead of /bin in the active PATH.

2

You can use the enable command to disable certain built-ins.

$ enable -n kill

However time is a keyword so this won't work.

$ builtin time
bash: builtin: time: not a shell builtin

So you're left with creating an alias to override it:

$ alias time=/usr/bin/time
slm
  • 369,824
  • nope. time is a shell keyword, not a shell builtin. I was just about to edit my question to say that enable -n does not work when I saw you had answered. – David Holdeman Aug 10 '13 at 15:45
2

Drop this into your ~/.bashrc:

alias time=/usr/bin/time

TravisThomas
  • 563
  • 1
  • 7
  • 13