I'm assuming you understand that both these commands are calling a different version of time, right?
bash's built-in version
% time
GNU time aka. /usr/bin/time
% \time
The built-in time
command to bash
can be read up on here:
% help time
time: time [-p] PIPELINE
Execute PIPELINE and print a summary of the real time, user CPU time,
and system CPU time spent executing PIPELINE when it terminates.
The return status is the return status of PIPELINE. The `-p' option
prints the timing summary in a slightly different format. This uses
the value of the TIMEFORMAT variable as the output format.
The GNU time
, /usr/bin/time
, is usually more useful than the built-in.
As to your precision problem it's covered here in this github gist, specifically:
Why is bash time more precise then GNU time?
The builtin bash command time gives milisecond precision of execution,
and GNU time (usually /usr/bin/time) gives centisecond precision. The
times(2) syscall gives times in clocks, and 100 clocks = 1 second
(usually), so the precision is like GNU time. What is bash time using
so that it is more precise?
Bash time internally uses getrusage() and GNU time uses times().
getrusage() is far more precise because of microsecond resolution.
You can see the centiseconds with the following example (see 5th line of output):
% /usr/bin/time -v sleep .22222
Command being timed: "sleep .22222"
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.22
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 1968
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 153
Voluntary context switches: 2
Involuntary context switches: 1
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
More resolution can be had using bash's time
command like so & you can control the resolution:
# 3 places
% TIMEFORMAT='%3R'; time ( sleep .22222 )
0.224
From the Bash manual on variables:
TIMEFORMAT
The value of this parameter is used as a format string specifying how the timing information for pipelines prefixed with the time reserved word should be displayed. The ‘%’ character introduces an escape sequence that is expanded to a time value or other information. The escape sequences and their meanings are as follows; the braces denote optional portions.
%%
A literal ‘%’.
%[p][l]R
The elapsed time in seconds.
%[p][l]U
The number of CPU seconds spent in user mode.
%[p][l]S
The number of CPU seconds spent in system mode.
%P
The CPU percentage, computed as (%U + %S) / %R.
The optional p is a digit specifying the precision, the number of fractional digits after a decimal point. A value of 0 causes no decimal point or fraction to be output. At most three places after the decimal point may be specified; values of p greater than 3 are changed to 3. If p is not specified, the value 3 is used.
The optional l specifies a longer format, including minutes, of the form MMmSS.FFs. The value of p determines whether or not the fraction is included.
If this variable is not set, Bash acts as if it had the value
$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'
If the value is null, no timing information is displayed. A trailing newline is added when the format string is displayed.
From the fine manual for bash(1)
:
ARGUMENTS
If arguments remain after option processing, and neither the -c nor the
-s option has been supplied, the first argument is assumed to be the
name of a file containing shell commands.
Does ls
contain shell commands? No, it is a binary file. bash
squawks about this fact and fails.
A strace
may help show what is going on:
$ strace -o alog bash ls
/usr/bin/ls: /usr/bin/ls: cannot execute binary file
The alog
file can get a bit messy, but shows bash
looking for ls
in the current working directory—a security risk if someone has placed a naughty ls
file somewhere!—and then does a PATH
search:
$ grep ls alog
execve("/usr/bin/bash", ["bash", "ls"], [/* 43 vars */]) = 0
open("ls", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/local/bin/ls", 0x7fff349810f0) = -1 ENOENT (No such file or directory)
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", X_OK) = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", R_OK) = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", X_OK) = 0
stat("/usr/bin/ls", {st_mode=S_IFREG|0755, st_size=117672, ...}) = 0
access("/usr/bin/ls", R_OK) = 0
open("/usr/bin/ls", O_RDONLY) = 3
As to why this could be a security risk, if you run bash somecmd
from the wrong directory where someone has created a ls
(or some other known command due to a bug in a script):
$ echo "echo rm -rf /" > ls
$ bash ls
rm -rf /
$
Best Answer
You can define an alias for
/usr/bin/time
as:Or
if you don't want to hard code the path to the
time
executable.The trick is in the trailing space in the alias definition that tells the shell that aliases must be substituted after that alias so that
Will actually be expanded to
(assuming
ll
is an alias tols -l
).In any case,
/usr/bin/time
being a standalone executable, it cannot time pipelines or compound commands or functions or shell builtins, so it cannot time the expansion of arbitrary aliases.If the reason for using
/usr/bin/time
is because you prefer its default output format over the one for thetime
keywork, note that in many shells, the format can be modified. For instance, inzsh
:(the
\e[31;m
for coloured (bold red) output).