There's a similar question that deals with the 'wrapping' scenario, where you want to replace for example cd
with a command that calls the builtin cd
.
However, in light of shellshock et al and knowing that bash imports functions from the environment, I've done a few tests and I can't find a way to safely call the builtin cd
from my script.
Consider this
cd() { echo "muahaha"; }
export -f cd
Any scripts called in this environment using cd
will break (consider the effects of something like cd dir && rm -rf .
).
There are commands to check the type of a command (conveniently called type
) and commands for executing the builtin version rather than a function (builtin
and command
). But, lo and behold, these can be overridden using functions as well
builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }
Will yield the following:
$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha
Is there any way to safely force bash to use the builtin command, or at least detect that a command isn't a builtin, without clearing the entire environment?
I realize if someone controls your environment you're probably screwed anyway, but at least for aliases you've got the option to not call the alias by inserting a \
before it.
Best Answer
Olivier D is almost correct, but you must set
POSIXLY_CORRECT=1
before runningunset
. POSIX has a notion of Special Built-ins, and bash supports this.unset
is one such builtin. Search forSPECIAL_BUILTIN
inbuiltins/*.c
in the bash source for a list, it includesset
,unset
,export
,eval
andsource
.The rogue
unset
has now been removed from the environment, if you unsetcommand
,type
,builtin
then you should be able to proceed, butunset POSIXLY_CORRECT
if you are relying on non-POSIX behaviour or advanced bash features.This does not address aliases though, so you must use
\unset
to be sure it works in interactive shell (or always, in caseexpand_aliases
is in effect).For the paranoid, this should fix everything, I think:
(
while
,do
,done
and[[
are reserved words and don't need precautions.) Note we are usingunset -f
to be sure to unset functions, although variables and functions share the same namespace it's possible for both to exist simultaneously (thanks to Etan Reisner) in which case unset-ing twice would also do the trick. You can mark a function readonly, bash does not prevent you unsetting a readonly function up to and including bash-4.2, bash-4.3 does prevent you but it still honours the special builtins whenPOSIXLY_CORRECT
is set.A readonly
POSIXLY_CORRECT
is not a real problem, this is not a boolean or flag its presence enables POSIX mode, so if it exists as a readonly you can rely on POSIX features, even if the value is empty or 0. You'll simply need to unset problematic functions a different way than above, perhaps with some cut-and-paste:(and ignore any errors) or engage in some other scriptobatics.
Other notes:
function
is a reserved word, it can be aliased but not overridden with a function. (Aliasingfunction
is mildly troublesome because\function
is not acceptable as a way of bypassing it)[[
,]]
are reserved words, they can be aliased (which will be ignored) but not overridden with a function (though functions can be so named)((
is not a valid name for a function, nor an alias