If you've declared a bash function, and then decided you don't really want it, either because you went ahead and implemented it as a script somewhere, or you gave it a bad name or something, you undeclare it like this:
$ unset -f myfunc
$ unset -f myfunc
which command reminded me of another wrapper function that's handy to have. If you use pushd/popd to keep a stack of directories in your shell window, sometimes you want to switch to a directory far down the stack. If you want to switch to the third directory down, you do pushd +3.dirs, pushd, and popd all just spit out a one-line list of the stack, like this:Not an impossible task, but it can get annoying if you have some long paths in there, especially once your stack gets past two or three deep. Why not have
$ dirs
/usr/local/share ~ ~/work ~/tmp
dirs print one directory per line, and label them with their depths? To do so, add this function to your .bashrc file:Now you get more readable output:
function dirs {
ds=(`command dirs`)
i=0
while [ "${ds[$i]}" != "" ]; do
echo $i: ${ds[$i]};
i=$((i+1));
done
}
If you want to remove
$ dirs
0: /usr/local/share
1: ~
2: ~/work
3: ~/tmp
~/work from the stack, just do popd +2.pushd and popd also print the directory stack, let's add the same style of output to them:One final note. In case some wacky systemwide file has aliased these commands to something else, add the following unaliasing code to the top of your .bashrc:
function pushd {
if command pushd $@ > /dev/null; then
dirs
fi
}
function popd {
if command popd $@ > /dev/null; then
dirs
fi
}
Otherwise, your functions will be hidden (aliases take precedence).
for func in dirs pushd popd; do
if alias $func > /dev/null 2>&1 ; then unalias $func; fi
done
which command is useful for searching your $PATH to find which version of an executable is going to run. But did you know that it doesn't always tell you the truth? For instance, it doesn't tell you when the command you're asking about is hidden by a shell builtin (or function, keyword, or alias):
$ which echo
/usr/bin/echo
which found /usr/bin/echo on your path, but echo is a shell builtin (at least in bash), so that's what will get run, not the one on the path. The GNU man page for which presents workarounds that will pick up functions and aliases, but shell builtins still slip through the cracks. The situation is even weirder on Solaris, where which is a csh shell-script, that sources your .cshrc file as part of its operation -- very strange if your shell is bash.which is not to be trusted. The easiest workaround, if you use bash, is the type builtin:
$ type -a echo
echo is a shell builtin
echo is /bin/echo
bash function for which, that uses type to do the right thing. I also like which to do an ls -l where applicable. Here's what I have in my .bashrc:
if alias which > /dev/null 2>&1; then unalias which; fi
function which {
hash -r
t=`type -t $@`
if [ -z "${t%%file*}" ]; then
for p in `type -p $@`; do
ls -l ${p};
done
else
type $@;
fi
}
which gives you much more information:
$ which -a wish
lrwxrwxrwx 1 root root 13 Dec 23 2008 /usr/local/bin/wish -> /usr/bin/wish*
lrwxrwxrwx 1 root root 7 Jan 8 2007 /usr/bin/wish -> wish8.3*
hash clears the hashed function list, so that any changes to your PATH are reflected. The reason for the if statement in the function, is that we certainly want to report builtins, functions, etc., but if there are none, we can use type -p to make it easier to pass the filenames to ls -l. If there are builtins or such, we just punt and give the unaltered type output.-a to this which if you want to see all the matches for the command, in order of precedence.