Order of executables started in bash
Solution 1
Highest priority is bash alias, then special builtins (only in POSIX mode), then functions, then builtins, then a search in $PATH
.
To execute a builtin, use builtin test
.
To execute an external application, use an explicit path: /bin/test
.
To ignore functions and aliases, use command test
.
To bypass just alias, use \test
or any other kind of expansion.
It's possible to disable/enable a builtin with enable test
.
(Updated according to comments below)
(Fixed incorrect admin edit that bash has disable
builtin - in fact, there is only enable
)
Solution 2
Built-in commands are always preferred to external commands. The rationale is that the built-in command is faster (and in a few cases, such as cd
or test -o BASH_OPTION
, only the built-in command can have the desired effect).
Sometimes the external command may have capabilities that the shell builtin doesn't. In that case, you can call the external command by giving an explicit path (i.e. containing a slash) (this bypasses any concern about the order in $PATH
). If you don't want to hard-code the external path but you do want to prevent the use of the builtin, you can use "$(type -P test)"
(note capital P
) in bash, "$(whence -p test)"
in ksh, and =test
in zsh.
Another way to force the use of an external command is to go through the env
utility (env test …
).
In zsh, you can disable a builtin with disable test
. This is permanent (for the current shell or subshell) until the builtin is reenabled with enable test
. In bash, you can do the same with enable -n test
to disable and enable test
to reenable.
You can use an alias or function to force the execution of a different command, for example alias test=/usr/bin/test
or test () { /usr/bin/test "$@"; }
. If you have such an alias, you can prevent its use by quoting any part of it, e.g. \test
will perform the normal function/builtin/external lookup. Note that depending on the shell and its settings, alias definitions in a function may be expanded when a function is read or when it is executed. If you've defined a function, you can use command test
to prevent function lookup as well as alias lookup (so here the test
builtin will be invoked unless disabled).
Related videos on Youtube
![comeback4you](https://i.stack.imgur.com/QKqMD.jpg?s=256&g=1)
comeback4you
Updated on September 18, 2022Comments
-
comeback4you almost 2 years
If I execute the
test
command in bash,test
(evaluates conditional expression) built-in utility is started:$ type test test is a shell builtin $ type -a test test is a shell builtin test is /usr/local/bin/test test is /usr/bin/test $
However, as seen in output of
type -a test
above, there is anothertest
in /usr/local/bin directory and yet another one in /usr/bin directory. How are executables ordered, i.e. are the built-in commands always preferred and then the rest of the commands depend on the directory order in $PATH variable? In addition, is it possible to change the order of the executables started, e.g. if I type intest
, then /usr/bin/test is started instead of bash-builtintest
?-
jasonwryan about 10 yearsYou can specify the full path when calling the command, eg.,
/usr/bin/test -f "$file"
... -
comeback4you about 10 years@jasonwryan I'm aware of this, but I'm just interested if there is a way to change the order of executables started.
-
-
Mathias Begert about 10 yearsThe order you have specified is different than the order mentioned in an answer from one of the gurus on this site. Which one is right?
-
Gilles 'SO- stop being evil' about 10 years@1_CR gena2x is right. My answer omitted special builtins, which take precedence over functions as per POSIX (though some shells are not compliant; bash complies only in POSIX mode).
-
Olivier Dulac about 10 yearsAnd to bypass just the alias :
\test
(this will either start the builtin, or, if no builtin of that name or it is disabled, will start any function of that name, or look for it in the PATH) -
John Kugelman about 10 yearsSuggested edit: Aliases are disabled when you quote the command (or any part of it), as in
\test
or'test'
ortes't'
. -
gena2x about 10 yearsThat's not full picture. Seems any kind of expansion (in bash manual, all the substitution, tilde expansion and so on called expansion) disables aliases. I tried.
-
John Kugelman about 10 yearsQuote from the bash man page: "The first word of each simple command, if unquoted, is checked to see if it has an alias. If so, that word is replaced by the text of the alias. The characters
/
,$
, backtick, and=
and any of the shell metacharacters or quoting characters listed above may not appear in an alias name." -
gena2x about 10 yearsMy statement says that any kind of expansion prevents alias substitution. This comply to the man page which says that any word which contains no symbols out of restricted set will never been substituted. Your statement that unquoted words prevent alias substitution. Both statements comply to bash manual. My statement is just broader than your and still holds truth. If you think that my statement is not true, please provide an example of the expansion which doesn't prevent alias substitution.
-
twan163 over 7 years+1 for hints in helping me find the source of this information: it is in the bash man page, under the section COMMAND EXECUTION, second and third paragraphs.
-
papo over 5 yearsso, if the shell runs from BusyBox, are other, usually external commands from the same BusyBox considered as internals? e.g. I added full
df
to a PATH on first position, removed alias 'df',which df
shows /opt/bin/df, but df runs /bin/df -> busybox -
Gilles 'SO- stop being evil' over 5 years
-
Tinmarino almost 5 yearsIf the search is unsuccessful, the shell searches for a defined shell function named
command_not_found_handle
. -
papo over 3 yearsI bounced back to this issue. This is not a problem of
which
orcommand
ortype
. I concluded this to be a bug of that busybox (v1.1.1). It is prioritizing its compiled-in binaries over PATH. And even when a link: xxx -> busybox is removed, the program xxx still runs. This must mean that this old busybox was considering all compiled-in binaries to be built-ins. New busybox does not behave this way. Just another thing to consider. btwcommand -v
andtype
showsdf is df
ortouch is touch
and not /bin/touch. I think that is giving away it's considered to be a sort of internal. -
Gilles 'SO- stop being evil' over 3 years@papo I see the same behavior with the fairly recent Busybox 1.30.1 on Ubuntu 20.04. It makes sense to me that the “compiled-in binaries” — which you could also call “built-in utilities” — are considered builtins in the shell sense of the term. P.S. There was a mistake in my answer:
command -p
does not bypass builtins, only functions and aliases. -
papo over 3 yearson v1.22.1,
type touch
touch is /bin/touch
, on v1.1.1touch is touch
, removing touch symlink file, on 1.22.1, touch does not work, on 1.1.1 touch still works in shell. I don't like the fact that I can't upgrade something like df, date, touch, put new binary in PATH and use this upgraded version in a script without static path. There is no mention nowhere that applets compiled-in busybox are special. I don't argue it could not be, but if that is not a bug, the behavior should be stable and it should be noted somewhere. -
Gilles 'SO- stop being evil' over 3 years@papo Maybe this depends on compilation options (e.g. hush vs ash) rather than on the busybox version