I've been thinking a bit about this before and I think that not just one but a whole lot of additional streams would be useful. By default all commands would still use stdout and stderr only but you would be able to tell them to use other streams as well for their various data.
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.
It is possible already - you can do `command 2>&4` to separate the output from one command in a pipeline into its own stream, then do `command2 <&4` to pull from the further down the pipeline.
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.
Yeah it does require special-case syntax. When using bash's built-in time, the command is executed exactly the same way as if you weren't using time, which means the command can set variables or define functions in the current shell. For example, you can say
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.
...which (surprisingly) is a measurable amount. About 1 ms for `dash` and a whooping 9.5 ms for `bash` on a relatively slow CPU:
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.643s
1ms is on the order of process creation time, so not very relevant: The measured program itself requires process creation. Most programs run considerably longer than that (otherwise timing would not make much sense).
Wow — that is extremely surprising. I did not expect that behavior at all. Who the hell thought it was a good idea to let a builtin command absorb the pipe symbol?!
Just quoting it normally also works, apparently, as your excerpt from the man page suggests:
$ 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.000s
Since the article doesn't clarify on shell command priority, commands are search in order:
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.
A command takes a series of arguments, stdin/out/err pipes and returns an error code on completion.
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:
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.
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.
> 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" .
In both bash and zsh, you can force the shell to use $PATH for lookup (bypassing functions and shell builtins) by calling a builtin name with 'command' ('command time -l ls'). You can equivalently force a builtin with 'builtin', but that does not work with reserved words (and 'time' is a shell reserved word).
Yeah. Shell semantics can be pretty unintuitive sometimes. I often find it helpful to translate these ideas to standard programming language terms.
* 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.
Yeah, I don't think it's all that rare for sudo to be an optional package not installed by default in distributions. At least that used to be the case back when I used try various ones a lot more.
So also are /usr/bin/{cd,[,echo,pwd,fg,..etc} a lot of them having subtle differences with their corresponding shell builtins. Most of the time the differences are not worth the hassle to remember, unless you somehow end up on a system with a broken filesystem (for example where /lib or /usr/lib is destroyed) and need to rescue stuff.
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.
That's a funny implementation. It would end up being an infinite loop for any command that wasn't a builtin, or didn't have an identically named thing higher up the PATH. Like if you renamed it from /usr/bin/cd to /usr/bin/mycd.