Ever since ... well, forever, people have been telling me to try zsh. I have been a happy tcsh user since the beginning of time, and have never seen a reason to switch.
According to the documentation, zsh is a hybrid shell that combines all the useful features of tcsh and ksh, has somehow managed to find good features in bash to include as well (I wonder how that works, I've never managed to find any good features in bash, only annoyances) and adds some interesting new stuff on top.
The implied bloat of this alone has kept me away from zsh for a while. In fact, the binary is about the same size as bash. Which isn't bad, considering that bash takes all this space without offering any functionality and zsh offers heaps.
Being bored over the long weekend, I took a closer look at zsh and tried to teach it about the things I have grown to like in tcsh. This turned out to be surprisingly easy. In fact, the only mildly tricky bit was teaching zsh about the addictive run-fg-editor command, which I bind to ^Z and which is very addictive.
Six lines in my .zshrc do the trick, however:
# Emulate tcsh's run-fg-editor
run-fg-editor() {
zle push-input
BUFFER="fg %$EDITOR:t"
zle accept-line
}
zle -N run-fg-editor
Another annoyance is the way the backward-delete-word function likes to eat whole paths. As far as I know, only tcsh gets this right by default. That is, if I've got something like cd /usr/local/tools/xchains/arm/arm9 in my buffer and press ^W, I only want the arm9 to go away, not the whole path. You'd think that would count as sensible default. Like the run-fg-editor bit, this was also fairly easy to fix:
# Emulate tcsh's backward-delete-word
tcsh-backward-delete-word () {
local WORDCHARS="${WORDCHARS:s#/#}"
zle backward-delete-word
}
zle -N tcsh-backward-delete-word
After I got zsh behaving like tcsh, I checked to make sure that some of the constructions I use all the time still worked:
[204] (philip@carrot)~/tmp% touch foo [205] (philip@carrot)~/tmp% cp foo !#:1.orig cp foo foo.orig [206] (philip@carrot)~/tmp% [206] (philip@carrot)~/tmp% !204:s/foo/bar/ touch bar [207] (philip@carrot)~/tmp% !205:gs/foo/bar/ cp bar bar.orig [208] (philip@carrot)~/tmp% [208] (philip@carrot)~/tmp% !to touch bar [209] (philip@carrot)~/tmp% !cp cp bar bar.orig [210] (philip@carrot)~/tmp%
Yes - I'm a great fan of history substitution. And of the foreach loop and modifiers:
[210] (philip@carrot)~/tmp% mkdir foreach [211] (philip@carrot)~/tmp% cd !$ cd foreach [212] (philip@carrot)~/tmp/foreach% touch alpha beta gamma [213] (philip@carrot)~/tmp/foreach% foreach file (*) foreach> mv $file $file:u foreach> end [214] (philip@carrot)~/tmp/foreach% ll total 0 -rw-rw-r-- 1 philip philip 0 May 4 13:49 ALPHA -rw-rw-r-- 1 philip philip 0 May 4 13:49 BETA -rw-rw-r-- 1 philip philip 0 May 4 13:49 GAMMA [215] (philip@carrot)~/tmp/foreach%
I also make the occasional typo:
[215] (philip@carrot)~/tmp/foreach% iv GAMMA zsh: correct 'iv' to 'vi' [nyae]?
Excellent. :-)
I'll be playing with this some more... I'm particularly interested in learning about the "fully programmable completion". If I read the documentation right, it's like tcsh completion on acid. Sounds like fun.
My only worry is that zsh is the "shell of choice" in the build system at work. So who knows what kind of horrible voodoo rites I'll need to perform to have both a sensible interactive environment (which the default isn't) and be able to create bootable builds (which a sensible interactive environment surely can't).
It seems zsh offers the possibility to be started with a different set of dotfiles. I think together with modules (thanks again for that tip, Jan, I think I already told you I'm addicted), I should be able to hack something together.
Fun fun fun!
Copyright © 2005–2010 Philip Paeps
All rights reserved.