(no subject)
Hmmm. I think I've just found another genuine use for Bourne shell aliases, and it's almost as ghastly as my previous one (http://www.chiark.greenend.org.uk/~sgtatham/aliases.html).
So I often find myself tab-completing down a directory tree looking for a file to run less on, and I generally find that part way down I want to run ls on a directory (hitting Tab twice is all very well but doesn't give me the colour highlighting that my instincts have started to rely on in directory listings). Hence, I tend to have to keep flitting back to the beginning of the command line to switch the actual command between less and ls. Today I lost patience and decided what I really needed was a wrapper on less which detected when its single argument was a directory and turned itself into ls instead.
So. Attempt number one:
less() {
if test "$#" = 1 && test -d "$1"; then
ls "$@"
else
/usr/bin/less "$@"
fi
}
That's fine as long as less is where I expect it to be; but most of my .bashrc is maintained in CVS and shared across a number of rather different Unices, and not all of them keep their less binary in the same place. So if I can't reliably find less by looking in /usr/bin, where do I look next?
One obvious answer is to use `which less`. Not acceptable, though: which isn't universal across all the machines I use. How about `type -path less`? Nope – type is a shell builtin which knows about shell functions, so it outright refuses to give me a genuine path to less because it knows bash would really run the shell function instead. There really doesn't seem to be an easy way to instruct my shell ‘Find me the command you would have run on seeing less if it weren't for the existence of this shell function, and run it’.
But aliases are much easier to inhibit. You have only to prefix your command with a backslash (\less), and bingo. Aliases are expanded before any of the normal command-line processing, including backslash processing; so in the absence of an alias called \less, no alias expansion occurs, and then the backslash is removed before searching the path. So with a bit of cooperation between aliases and shell functions, we have a reasonably robust implementation:
bashrc_less_wrapper() {
if test "$#" = 1 && test -d "$1"; then
ls "$@"
else
\less "$@"
fi
}
alias less=bashrc_less_wrapper
This is utterly disgusting and I hope I've missed something. If this is really the best way to do what I want, I'm forced to the conclusion that not only are aliases a hideous misfeature (discussed at length in my Magic Aliases article), but shell functions are broken as well and aliases happen to be able to compensate for them once in a while. Ick.
no subject
no subject
no subject
commandappears to be the POSIXy way of suppressing function lookups, butenvis just as good in this case, and shorter. For a sillier approach, you could use a subshell:less() { if test "$#" = 1 && test -d "$1"; then ls "$@" else (unset -f less; less "$@") fi }