Is the shell permitted to optimize out useless terminating commands?
No, that would be a bad idea.
cat hugeregularfile.txt > /dev/null
and touch -a hugeregularfile.txt
are not the same. cat
will read the whole file, even if you redirect the output to /dev/null
. And reading the whole file might be exactly what you want. For example in order to cache it so that later reads will be significantly faster. The shell can't know your intention.
Similarly, a C compiler will never optimize out reading a file, even if you don't look at the stuff you read.
No, since /dev/null
is just a name, which could be used for any other device or for a file other than what "normally" is a data sink.
So a shell (or any other program) has no idea, based on the name, whether the file it is writing to is doing something "for real" with the data. There are AFAIK also no system calls the shell program can make, to determine that e.g. the file descriptor is actually not doing anything.
Your comparison with optimising away code in a C program does not work, as a shell does not have the total overview that a C compiler has over a piece of source code. A shell doesn't know enough about /dev/null
to optimize your example away, more like a C compiler doesn't know enough about code in a function call it dynamically links to, to not make the call.
It will not optimise out running commands (and you've already received a number of fine answers telling you why it should not), but it may optimise out forks, pipe/socketpairs, reads in some cases. The kind of optimisations it may do:
- With some modern shells, the last command in a script can be executed in the process of the shell unless some
trap
s have been set. For instance insh -c ls
, mostsh
implementations (bash
,mksh
,ksh
,zsh
,yash
, some versions ofash
) won't fork a process to runls
. - in
ksh93
, command substitution will not create a pipe or fork a process until an external command is called ($(echo foo)
for instance will expand tofoo
without a pipe/socketpair or fork). - the
read
built-in of some shells (bash
, AT&Tksh
) will not do single-byte reads if they detect stdin is seekable (in which case they will do large reads and seek back to the end of what they are meant to read).