set
isn't just a builtin, it is a POSIX special builtin. There are a few builtin commands which are standards-specified to be found in a command search before anything else - $PATH
is not searched, function names are not searched, and etc. Most builtins which are not special are actually required by the POSIX standard to be found in your $PATH
before the shell will run any of its own builtin procedures. This is true of echo
and most others (though whether the standard is honored in this respect has been a matter of contention at the open group mailing lists in the past), but not of set
, trap
, break
, return
, continue
, .
, :
, times
, eval
, exit
, export
, readonly
, unset
, or exec
.
All of these are reserved names of the shell, and they have special attributes other than their order of preference for command search as well. For example, you cannot define a shell function with any of those names in a standards-compliant shell. This is a good thing - it enables people to write portable scripts safely. These are baseline commands from which an experienced script-writer can establish a secure and reliable foothold in his or her environment. Invading this namespace is not advisable.
However, if you do desire to invade it, you can do so portably with alias
. The order of shell expansion enables this work-around. Because the alias
is expanded while the command is being read, whatever you replace the set
name with in your definition will expand correctly, it just probably should not expand to one of those names.
So you could do:
alias set=./set
...which will work just fine.
test
for basically the same reason;test
is a shell built-in too.test
seems to make sense. Of course by the time you put it in yourPATH
you really should have come up with a different name. And until you put the program in yourPATH
you'd have to invoke it as./test
anyway. So it is kind of OK to use the nametest
for a program as long as it is a quick test which you intend to delete before the end of the day.foo
.ls
then whenever you go to see if it exists it will run (but only if you modify your path as you did in the question).