Shell users like to tailor their environment to speed up common tasks. The alias mechanism is very handy for this, you bind a short idiom to the sequence you run a lot. For instance, I have this line in my alias list:
alias lh='ls --color -Flah'
Download this code: alias_lh
Having done that, you can also rig up a system of pulleys so that you can take the whole thing with you wherever you go.
All is well so far, but now comes the icky part. If you take this bundle of joy to murky neighborhoods like BSD or commercial Unices you’ll find out that the userland isn’t the same everywhere, even though you have the shell. BSD (DesktopBSD), for instance, doesn’t support the whimsical –color switch, they like monochrome.
So what to do? What I would like to have is the same alias bound to something that works on the given platform, let it degrade gracefully. The only way to know that is to test for it, then bind the alias accordingly. That’s what happens here, I try the incantation I want and if that doesn’t work, I use the failsafe one.
setalias() { if eval $2 &>/dev/null; then eval "alias $1='$2'" else eval "alias $1='$3'" fi } setalias "lh" "ls --color -Flah" "ls -Flah"
Download this code: alias_test
But this is still a bit lacking. You obviously set up the aliases to run at shell startup, not manually. But there are instances when you might need a new shell, but you might have high io latency, or the io might be locked up through a system error. In such a case, you really just want to do as much as is necessary to start the shell, without doing a lot of io stuff in the startup files. So running ls and things like that for the purpose of setting up an alias is to be avoided.
Here’s where an idea from compilers can help. First, let’s think about the setalias function as code to be executed. This code runs on shell startup. But it doesn’t have to. We could just as well bind the alias to the function code itself, to make it run the first time the alias is executed. That’s what happens here, the shell starts and binds the alias to a string. The first time the alias is executed, it runs the test and then does the binding. And then runs the actual command we wanted to run.
setalias() { alias "$1"="if eval $2 &>/dev/null; then eval \\"alias $1='$2'\\" else eval \\"alias $1='$3'\\" fi; eval $1" } setalias "lh" "ls --color -Flah" "ls -Flah"
Download this code: alias_deferred
It’s like a just-in-time compiler, we do some extra work the first time, but from then on it’s all set up.
There’s a lot more you can do with eval, so go nuts!
