Automatically Expanding zsh Global Aliases As You Type

| Comments

Animated demonstration of globalias

Update 2012-11-04: This page is now out of date. Since this entry was published, I cleaned this code up quite a bit. You should definitely check out the new entry.

I am not the first person to think of this idea. My notes seem to think that I originally found the idea on the zsh wiki and I stole the code I started with from hackerific.net.

What are global aliases?

Shell aliases let you condense a long-winded and/or hard-to-remember command down to a short, easy-to-remember word. Old-school shells will only match the alias if it is the first word in the command. Zsh lets you take that one step further by allowing you to define aliases that will be substituted no matter where they appear on the command line. These are global aliases.

Here is one of my global aliases that I use all the time:

1
alias -g G='|& egrep -i'

With this alias defined, these two commands are equivalent:

1
2
cat /proc/cpuinfo G cache
cat /proc/cpuinfo |& egrep -i cache

My problem with global aliases

When I look at a command line with a global alias, it isn’t always entirely clear to me what the command I am about to run is actually going to do. Am I sure my G alias has a -i switch? Does it use |& so that it will also grep stderr?

The existing solution

The handy script at hackerific.net sets things up so that as soon as you hit the space bar after typing the global alias, it is automatically expanded right there on the command line.

This is great for a couple of reasons. You never have to guess what code is hidden inside that alias. The full text of the command will be right there on the command line and in your history, so you’ll never be surprised. It also means you can go back and tweak the command a bit.

What I did differently

There is only one thing I didn’t like about the solution at hackerific.net. Instead of cleanly defining your global aliases with the alias command, you have to add your aliases into a hash table. His code uses that hash table to expand the aliases on the command line and also to create your actual global aliases (so that they still work at the end of the line).

I like that you only have to define them once, but I wanted to build the hash table out of the global aliases that are already defined.

I managed to parse the output of alias -g and stuff it into the hash table, but I wasn’t able to make it work without piping the output to Perl and sourcing the output back in. I tried to make it work with pure shell code, but none of the magic I came up with worked.

Deprecated globalias code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typeset -A abbrevs

# Begin Ugly Hack

alias -g | perl -e "print 'abbrevs=('; while (<>) { s/^(.+?)='(.+)'/'\$1' '\$2' /g; s/'\\$/\\$'/g; print; } print ')';" > /tmp/cheater.zsh
source /tmp/cheater.zsh

# End Ugly Hack

globalias() {
   local MATCH
   LBUFFER=${LBUFFER%%(#m)[_a-zA-Z0-9\-]#}
   LBUFFER+=${abbrevs[$MATCH]:-$MATCH}
   zle self-insert
}

zle -N globalias

bindkey " " globalias
bindkey "^ " magic-space           # control-space to bypass completion
bindkey -M isearch " " magic-space # normal space during searches

You can probably just paste this into your .zshrc near the end, after all your global aliases are defined.

oh-my-zsh plugin

I’m running my copy as an oh-my-zsh plugin. I haven’t uploaded it to github yet, though. I’d prefer to eliminate the ugly pipe-and-source lines first. I may have to upload it as is if I don’t get around to improving it, though.

You can download my plugin here. It is identical to the code above.

Comments