Here’s an approach that I believe is
slightly less messy than Gilles’ answer
(although I concede that to be a subjective judgment).
#!/bin/sh
this_dir=$(dirname "$0") # Alternatively, hard-code this as this_dir=$HOME/bin
redacted_PATH=$(echo ":${PATH}:" | sed -e "s:\:$this_dir\::\::" -e "s/^://" -e 's/:$//')
if obscured_prog=$(PATH=$redacted_PATH which foo)
then
⋮ # Munging to do before running /usr/bin/foo
"$(obscured_prog)" argument(s) # may be "$@", but might not be.
⋮ # Munging to do after running /usr/bin/foo
else
echo "$0: foo (real) not found in PATH."
⋮ # Any code that you want to do anyway.
fi
This constructs redacted_PATH to be $PATH
minus the $HOME/bin directory where this private copy of foo lives.
echo ":${PATH}:" adds colons to the beginning and end of $PATH,
so every component of it will be preceded and followed by a colon —
even the first and last one. The sed searches for
: $this_dir :
(with spaces added for “clarity”) and replaces it with
:
i.e., it excises $this_dir from ":${PATH}:".
It then removes the colons from the beginning and end.
Then we temporarily set PATH to $redacted_PATH
and search for foo using which.
If successful, we get a full path to it (e.g., /bin/foo or /usr/bin/foo),
which we use to run the real (public/shared/system) copy of foo.
Since we changed PATH only temporarily,
/bin/foo has access to the user’s ambient $PATH,
and so, if /bin/foo runs brillig, it can find $HOME/bin/brillig
(if it exists).
This will have a problem if $HOME/bin appears in $PATH multiple times,
but that’s not too hard to remedy.
foomight in turn invoke other commands, some of which may be in the same directory as thefoowrapper. – Gilles 'SO- stop being evil' Apr 02 '15 at 23:41/usr/bin/foois accessing "private" commands like/home/bob/bin/foo? - At best that appears to me to be a misdesign. – Janis Apr 03 '15 at 09:48/bin/shwith the expectation that it runs “private” commands. Or run programs in/usr/binthat invoke an editor which is~/bin/EDITOR. Etc. – Gilles 'SO- stop being evil' Apr 03 '15 at 11:49alias mv="mv -i". More complicated examples need to be done in shell functions or scripts. … (Cont’d) – G-Man Says 'Reinstate Monica' Apr 29 '15 at 21:00/bin/ps2htmlis a script that runsgs(Ghostscript) without specifying a path. Suppose I have wrapped/bin/gswith a front-end~/bin/gs. If I have~/binbefore/binin my search PATH, then, when I run/bin/ps2html, I probably want it to run~/bin/gs(which will probably invoke/bin/gswith a tweak) — even/especially if I am running/bin/ps2htmlfrom a~/bin/ps2htmlfront-end. – G-Man Says 'Reinstate Monica' Apr 29 '15 at 21:01foomight in turn invoke other commands, some of which may be in the same directory as thefoowrapper, then change PATH *without exporting it, so, when~/bin/foosays “foo”, it will get/usr/bin/foo, but, when/usr/bin/foosays “bar”, it will use the original*$PATH, which it gets from the environment, and so it can find~/bin/bar. – G-Man Says 'Reinstate Monica' Apr 29 '15 at 21:05