Recently in unix Category

Sun sells cshells...

April 5, 2006 11:27 AM

well, actually Sun doesn't sell much of anything notable anymore. But back when I started playing with Unix, Sun workstations were golden, and SunOS was the standard by which all other Unixes were judged. 4.1.3U1 was rock solid, fast and ran on neat Sparc hardware.

And with it came the cshell. Well, of course it came with the original Bourne shell, but that was just for scripting, right? Surely nobody used that dinosaur interactively, right? Did it even have command history?[1] And ksh - that was like the Scientology of shells[2] - it was always around, but only the kooks used it. Everybody used /bin/csh, because that was just The Right Thing, and there was little argument.

Except, of course, from the ubernerds using tcsh[3]. The arrow keys were useful! It had filename completion! It understood terminfo! It was badass timesaver for anybody who sat in front of a shell all day.

That was over a decade ago, and my login shell is still tcsh. I haven't even thought about it in the last ten years -- meaning I've probably used it more than any other single piece of software in my lifetime[4]. And then, the Linux guy - my former tcsh-using colleague - questioned my choice of interactive shells. He was creating an account for me on some server and realized, "oh, I have to install tcsh so you can login."

What!? It's tcsh, it's the standard... well, maybe that should be was the standard...

% echo $version
tcsh 6.12.00 (Astron) 2002-07-23 (powerpc-apple-darwin) options 8b,nls,dl,al,kan,sm,rh,color,dspm,filec

There hasn't even been a point release in almost four years. Yeah, maybe that's a positive on me being behind the times. So I dusted off my scruffy Unix-guy beard and ran that scary chsh command. After a little playing, here's why I'd recommend you make the plunge and dig into zsh over tcsh:

  • Extended aliases
    tcsh lets you alias a command, but zsh lets you alias arguments, too. Global aliases (alias -g) match any position. So you could, for example, work around annoyances with system utilities. On a Mac, /tmp is a symlink, and you rarely want to operate on the symlink, but almost always want to operate on the directory. tar -cf tmp.tar /tmp? Not very useful. Thus:
    alias -g '/tmp'='/tmp/.'

    You can also alias file extensions to map to programs to execute. Let's say you have some .NET programs (for example: Vault[5]) as .exe files:

    alias -s exe=mono

    will let you type vault.exe, and will execute mono vault.exe. Beautiful!

  • Directory history
    Sure, tcsh has pushd and popd, and they're surpremely handy if you're disciplined enough to actually use them. I've never been that disciplined, and I always end up shooting myself in the foot when I leave the insane depths of a source tree to go into my home directory or /tmp for a second. Solution?

    setopt AUTO_PUSHD

    Now instead of kicking myself for not running pushd, I just popd back to where I was before. Handy.

  • Multi-line history editing
    This one's a no-brainer. tcsh's history editing stinks. Do a foreach, make a mistake inside the block, and then try to go back and change it. Nope. zsh pops up the entire block. (Heck, even bash does this right.)

  • Better single line history
    Let's say you edit a file in a faraway directory, do a few dozen things and forget where that file was. In tcsh, if you know the line number, you may able to get that faraway path back. In zsh, if you remember part of it, you're better off:

    vi /Users/ethomson/tmp/project-1.0/src/libproject/Makefile
    ...
    ...
    !?Makefile

    will search your history for Makefile and bring up the most recent. Want to do something else with that file, instead of running vi? Try:

    cat !?Makefile?:1

    (the first parameter from the matching line.) Or, try:

    !?Makefile<TAB>

    to bring up the whole command from history on your prompt, for editing.

  • Smarter shell builtins
    It surprises me how often I use foreach to do renames. Backing up a group of files -- or worse, restoring them. Previously I might have done:

    foreach a ( *.log.bak ) set b=`echo $a | sed -e "s/\.bak$//"`
    mv $a $b
    done

    zsh's builtin zmv makes this easy:

    zmv -W '*.log.bak' '*.log'

  • Math!
    Despite majoring in math, I never was very good at arithmetic. But neither is tcsh. On the other hand, zsh has math builtin. Let's say I want to add track numbers to some music files[6] in tcsh:

    set cnt=0
    foreach a (*)
    set cnt=`expr $cnt + 1`
    mv $a $cnt-$a
    end

    But in zsh:

    cnt = 0;
    for a in *; do
    mv $a $((cnt=cnt+1))-$a
    done

    (Okay, so you only save one line, but you also don't have to remember that expr has such a broken tokennizer that it can't understand the difference between "0+1" and "0  +  1"

I'm very pleased with zsh. Even if its improved history, better aliasing and better directory traversal only shave a little bit of time off my shell usage, that adds up over the course of a week - and maybe it makes me a little less grouchy[7]. In the little bit of time I set aside for learning new zsh features, I found the the zsh wiki to be super-helpful.

  1. No
  2. Sorry Jeremy... ;)
  3. Nobody I knew had ever heard of bash until those crazy first Linux distributions came out, at which point its familial heritage was called into question on several occasions.
  4. vi would be first if it weren't for the transition to nvi in 4.4BSD and the widespread adoption of vim by linux distributions (despite its incorrect undo syntax.)
  5. You'd be correct if you recognized this as shameless corporate promotion.
  6. Globbing the filenames with * will obviously only work if the filenames are track-ordered. For the purposes of this example, let's assume filenames are song names and the album's tracks are in alphabetical order. This isn't completely contrived: see the excellent (and alphabetical) The Magnetic Fields: i.
  7. My co-workers may, of course, disagree...
Edward Thomson is a Software Engineer at Teamprise, where he develops cross-platform client solutions for Microsoft Team Foundation Server, with an emphasis on Macintosh compatibility and IDE integration.