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.
foo
might in turn invoke other commands, some of which may be in the same directory as thefoo
wrapper. – Gilles 'SO- stop being evil' Apr 02 '15 at 23:41/usr/bin/foo
is 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/sh
with the expectation that it runs “private” commands. Or run programs in/usr/bin
that 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/ps2html
is a script that runsgs
(Ghostscript) without specifying a path. Suppose I have wrapped/bin/gs
with a front-end~/bin/gs
. If I have~/bin
before/bin
in my search PATH, then, when I run/bin/ps2html
, I probably want it to run~/bin/gs
(which will probably invoke/bin/gs
with a tweak) — even/especially if I am running/bin/ps2html
from a~/bin/ps2html
front-end. – G-Man Says 'Reinstate Monica' Apr 29 '15 at 21:01foo
might in turn invoke other commands, some of which may be in the same directory as thefoo
wrapper, then change PATH *without exporting it, so, when~/bin/foo
says “foo
”, it will get/usr/bin/foo
, but, when/usr/bin/foo
says “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