/usr/bin/time: not the command you think you know
hackernoon.com
hackernoon.com
time foo |bar
Then the result is the total time taken by foo and bar together. This requires it to have special-case syntax. Whereas /usr/bin/time foo |bar
Would run foo and give its time statistics as input to bar. time {
sleep 0.1
sleep 0.2
}
# result is 0.3 seconds
which you obviously can't do with an external command. I wrote about that here:https://lobste.rs/s/hwgt2h/usr_bin_time_not_command_you_thin...
/usr/bin/time foo |bar
would actually give the output of foo as input to bar, since the time statistics go to stderr.http://unix.stackexchange.com/questions/197809/propose-addit...
Furthermore, each stream should be possible to pipe to a different process if you wish independently of the other streams.
To a small degree this might be possible already with named pipes.
I think socket pairs would be great for it.
Nothing implemented yet!
I still don't use it enough, but when it comes to scripting PS's objects beat the hell out of these
This would allow many things, for example searching for multiple terms across all files in the whole file system in one go without opening each file more than once, and then grouping the different results together in accordance with the term that they matched.
time echo | sleep 1
vs. /usr/bin/time echo | sleep 1
The former times the entire pipeline whereas the later only times the first command in the pipe.echo | /usr/bin/time sleep 1
As an example :
sleep 2 | /usr/bin/time sleep 1
This gives an output of "1 second" even though the entire pipeline took 2 seconds.
time sh -c 'foo | bar' pi@pi:~ $ time (for x in {1..1000}; do time echo | sleep 0.01; done 2>/dev/null)
real 0m24.173s
pi@pi:~ $ time (for x in {1..1000}; do time sh -c 'echo | sleep 0.01'; done 2>/dev/null)
real 0m25.170s
pi@pi:~ $ time (for x in {1..1000}; do time bash -c 'echo | sleep 0.01'; done 2>/dev/null)
real 0m33.643sIt's really not more than that: an optimization.
time foo=bar
echo $foo
and it will correctly print out "bar". It can't do this if it executes the command in a subshell. Or similarly you can say `time cd /foo` and it will actually change the current working directory. $ \time echo
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 1764maxresident)k
0inputs+0outputs (0major+66minor)pagefaults 0swaps
The built-in version: $ time echo
real 0m0.000s
user 0m0.000s
sys 0m0.000s> The first word of each simple command, if unquoted, is checked to see if it has an alias.
I observe that t\ime works just as well as \time.
$ help|head -1
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
$ "time" --version
GNU time 1.7
$ time --version
bash: --version: command not found
real 0m0.001s
user 0m0.000s
sys 0m0.000sI think it's because using the backslash to escape counts as quoting. So the following are all equivalent:
$ \time foo
$ t\ime foo
$ 'time' foo command time echo
The usage of the `command` keyword makes it ignore shell functions (including built-in shell keywords like time).1. Alias expansion.
2. Defined shell functions.
3. Built-in shell functions.
4. Command path.
If you provide an unqualified command that matches more than one of these elements, the first match wins.
Prepending a backstroke: "\command", will inhibit alias expansion. E.g.:
alias date="echo no date"
date
\date
Should return "no date", and your current system date, respectively.To invoke a system command directly, call the full path. If you don't feel like running the fish shell (not that there's anything wrong with that).
Some simple shells (e.g., dash, and IIRC the original Bourne shell, though that is not what you'll find as /bin/sh on most modern systems) don't include a time builtin, and can invoke the system time command directly.
$ command time --version GNU time 1.7
https://www.gnu.org/software/bash/manual/html_node/Pipelines...
time prefixes a pipeline ( the most basic case being a single command without a pipe into another ), a command block { ... } a subshell block ( ... ), a for statement, an if statement, just whatever really.
This "time" would output how long "a" took to run:
/usr/bin/time a b c | { d e ; f g ; } | h i ;
This "time" outputs how long the pipeline "a", "d", "f", and "h" took to run: time a b c | { d e ; f g ; } | h i ;
This is a syntax error: /usr/bin/time { d e ; f g ; }
This returns how long the command group takes to run: time { d e ; f g ; }
Further examples: $ time sleep 10 | sleep 1 ;
real 0m10.073s
user 0m0.000s
sys 0m0.000s
$ time sleep 1 | sleep 10 ;
real 0m10.003s
user 0m0.000s
sys 0m0.000s
$ /usr/bin/time sleep 10 | sleep 1 ;
0.00user 0.00system 0:10.00elapsed 0%CPU (0avgtext+0avgdata 1796maxresident)k
0inputs+0outputs (0major+80minor)pagefaults 0swaps
$
$ /usr/bin/time sleep 1 | sleep 10 ;
0.00user 0.00system 0:01.00elapsed 0%CPU (0avgtext+0avgdata 1808maxresident)k
0inputs+0outputs (0major+82minor)pagefaults 0swaps
Note the two /usr/bin/time's output their timing information as soon as the first command is done, but the pipeline doesn't return until both commands have exited.> hope this rant helps in some way
What of:
/usr/bin/time ( sleep 1 | sleep 10 )
Explicitly invvoking a subshell. Which I understand the builtin to be doing.Yep, it's the same as /bin/test, but basically requires the last argument to be a ]. Typically /bin/test and bin/[ are hard links, that is, they are physically the same file and share the same inode(s).
You know, so you can type
if [ $foo = $bar ]; then
yes
else
exit
fi
This actually runs the command /bin/[, except most of the time it doesn't, because it's built-in to the shell.As as side-note, an article like this should at least mention which OS and shell the author is using.
Very much agree! I just tried this on my 2.6.32 RHEL system, and it's never heard of "-l". It outputs very similar-looking information as in the article, though, when given "-v" .
http://unix.stackexchange.com/questions/267761/differences-b...
* Commands are like functions * Commands in /bin etc. are like library functions * Builtins are like a language's primitive functions * Keywords are keywords
$ which time
time: shell reserved word
$ ls /usr/bin/time /bin/time
ls: cannot access '/usr/bin/time': No such file or directory
ls: cannot access '/bin/time': No such file or directory
Looks like something specific to the author's distribution.GNU source: http://git.savannah.gnu.org/cgit/time.git/tree/
BSD source: https://github.com/freebsd/freebsd/blob/f5d95e1f8d32db4ccccf...
Busybox source: https://github.com/mirror/busybox/blob/f88e3bfa8ded4f1c7e7d2...
Toybox source: https://github.com/landley/toybox/blob/master/toys/posix/tim...
This would have been a lot easier if I'd known GitHub has a `filename:` search
$ time ls / bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
real 0m0.004s
user 0m0.000s
sys 0m0.000s
$ /usr/bin/time ls /
bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 2304maxresident)k
0inputs+0outputs (0major+109minor)pagefaults 0swaps
Edit: formatting
Which gives new meaning to the relativity and vagueries of time....
\time --verbose echoIt did seem odd to me that the author didn't bother to mention which OS he is using, though from the hostname I have a pretty good guess.
"/usr/bin/time: not the command you think you know" -> "/usr/bin/time: may not be the command you think you know"
There, I fixed the title.
$ pacman -Fo /usr/bin/time
usr/bin/time is owned by extra/time 1.7-8
If that command doesn't work for you, try adding "-y". `man pacman` for details.Guessing it isn't terribly useful.
#!/bin/ksh -p
# ...
cmd=`basename $0`
$cmd "$@"
I just noticed that the what(1)-string (I haven't seen on of those for a long time) references "alias.sh", perhaps this is a clue? #ident "@(#)alias.sh 1.2 00/02/15 SMI"
Were builtins actually aliases in an early shell? I still don't understand how this works though. #!/bin/sh
# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
# This file is in the public domain.
builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}You guess correctly. The issue is that POSIX states that
... all of the standard utilities [...] shall be implemented in a manner
so that they can be accessed via the exec family of functions as defined
in the System Interfaces volume of POSIX.1-2008 and can be invoked
directly by those standard utilities that require it (env, find, nice,
nohup, time, xargs).
Note however that /usr/bin/cd isn't completely useless: It has the same diagnostics (error message and exit code) as the command, so `env cd $FOO` is a way to check if you can change to that directory without actually doing it.