Thu, 22 Jun 2006
Life in Text Mode
I primarily use Unix-based computers, mostly Linux. On those computers, I live in text mode. This entry is an attempt to document the software I find most useful to my text-mode guerrilla lifestyle. Included are links to the programs I rely on, links to alternative programs, and links to my config files.
My shell of choice. Think of all the good features of bash, ksh, and
tcsh rolled together. (Without much of the ickiness, particularly the
csh heritage.) Personally, the killer application of zsh was that
fact that not only did it have context-sensitive completion but
(unlike tcsh) it shipped with hordes of completion definitions right
out of the box. Type '
dpkg -L fo<tab>' and zsh
will autocomplete on the Debian packages currently installed on your
system. With an ssh-agent running, type '
otherhost:fo<tab>' and zsh will ssh to the other system
and autocomplete on the files available on that host.
bitlbee. This is actually an IRC-to-Instant-Messaging gateway. It allows me to use AIM, Jabber, and the like from within my preferred chat program, irssi.
snownews. curses-based RSS aggregator. I shopped around a bit before finding an aggregator that I liked. snownews does everything I need.
mutt (.muttrc, config directory). Possibly the best mail client around, GUI or not. While pine is okay (and simpler to use), mutt is much more customizable and scales better to large volumes of email.
procmail (.procmailrc). Slices and dices my email. I have procmail rewriting things so they're easier for me to deal with, sorting my list mail into separate mailboxes (automatically; no need to add new lists by hand), and checking (and dealing with) spam. Essential to my email usage.
Emacs (.emacs). My text editor of choice. Feel free to substitute XEmacs or vi (preferably vim) at your own preference. I prefer emacs to vi, though I know a decent amount of vi, as any sysadmin should. I actually like XEmacs a little better than GNU Emacs, but GNU Emacs has better UTF-8 support.
w3m. Web browser. Among other things, w3m does tabbed browsing, though it's not multithreaded, so you can't read one tab while another is loading. It even has image support; run it with a valid $DISPLAY and it'll render images on the page. There are other text-mode browsers, most notably links. I'm not tremendously familiar with links because w3m fills all of my needs. (My original decision between the two came about because w3m had better HTML support, but I don't believe this is any longer the case.) The grandaddy of text-mode browsers is, of course, lynx, but it's lagged far behind w3m and links in support for newer aspects of HTML.
moosic (config). This is a music jukebox. The features that distinguish it from other such programs are twofold. First, it runs as a standalone server; you interact with it via a command line client. (In theory, a curses or GUI client could be written, but to my knowledge none yet has.) Second, it's customizable with regards to how it plays music. It has a config file where you tell it what programs to use to play various music formats (it does come with reasonable defaults). A program with similar design is mpd. mpd does its own music playing, which allows some advantages over moosic, but moosic has much better playlist management.
mplayer (config). Okay, this is kind of a hedge. I do indeed use it purely in text mode on occasion--it has better support for streaming media (usually mp3s) than any of the actual mp3 players I use. mplayer's main advantage is that it will play pretty much any video format I throw at it. (I'm not quite masochistic enough to watch the videos in aalib, though.)
surfraw is a collection of command-line based jumping-points to
various web-based information, mostly searches. For a quick google
search, I need only go to a command line and type '
my search terms'. (Debian uses a single program,
sr', as a wrapper for all of the surfraw "elvi". On
other systems, you would probably just run '
wget. The swiss-army-knife of grabbing things off the web (and via FTP). I've automated many downloads, some tweaked in interesting ways, with wget.
tdl. Completely command-line todo list manager. Along similar lines is DevTodo; I haven't really played with it because tdl does everything I need. Those two are both command-line based. For more of a todo list editor, you might want to take a look at hnb or woody. (Though, of those two, hnb has better support for todo lists.)
Those are the bigger programs that jump to mind most readily. I use a host of other programs, too. Listed briefly, they are: less (pager), mpg321 (mp3 player), GnuPG (OpenPGP implementation) (options), aumix (volume control), teTeX (TeX implementation), pal (nice colored calendar with a number of features), bc (simple command line calculator), dict (actually a dictionary network protocol but their command-line client is also named 'dict'), mp3gain (normalization of mp3s (ideally should be done non-destructively via ID3v2 but no one supports that)), netcat (connect directly to TCP sockets), BitTornado (bittorrent client; slightly nicer than the standard one), subversion (source revision control; nicer than cvs), abcde (CD ripper) (.abcde.conf), lame (MP3 encoder), nmap (portscanner), hping (packet generator), and tcpdump (packet sniffer).
There are a couple of GUI programs I use regularly. I've already mentioned mplayer; you really need a pixelmapped interface to watch movies. There's also Ethereal, an excellent network sniffer and protocol analyzer (much nicer than plain tcpdump), and GnuCash, one of the best asset management programs I've come across. (But see clacct for straight command line checkbook balancing.) Oh, and Firefox, for those websites that just won't work with w3m.
War of Honor
It's past five in the morning. I've been up reading for almost the last four hours because I wanted to finish the book. It's good. The pace is much slower than I remember previous Honor Harrington books being, but things do move along.
Reading all of the Honor anthologies before this book is highly recommended.
Wed, 07 Jun 2006
Ruby vs. Python (vs. Perl) (vs. Lisp)
I've recently been playing with Ruby, and I think I've finally found a replacement for my various uses of Perl. For a while now, I've been using one of two languages for my at-home programming: Common Lisp for the more complex or interesting tasks; and Perl for the simpler tasks, standalone programs, and one-line text processing.
I've long had a love/hate relationship with Perl. On the one hand, its
DWIM approach to things make it easy to do simple things, especially
one-off text munging.
perl -pe '<stuff>' has long been my friend. It
also has CPAN going for it; many of my problems have been solved with a
CPAN module and a little glue code. On the other hand, Perl tends towards
extreme ugliness, especially when the code starts to get complicated.
I've never liked the OO interface for Perl, for example; not only does it
feel very obviously bolted on to an existing infrastructure, it didn't
even get the sharp, pointy edges sanded down when they did it.
Thus it was that I was impressed with Python when I first met it. It
felt like a language designed with OO from the bottom up. (But it wasn't;
the addition of OO stuff had just been done in a much better way than
Perl's.) It had nice data introspection. It had functions as first-class
objects (so they got the benefit of introspection, as well as the other
benefits of first-classness). I figured I could live with the
whitespace-as-syntax wart. As I got to know it more, Python started
falling down in a few places. For one thing, Guido van Rossum apparently
doesn't like functional programming. Python has some functional
programming constructs, like map and filter, but Guido keeps threatening
to remove them. There's no good way to create anonymous functions,
lambda is only useful for relatively trivial purposes.
Python is also not terribly useful from the command line, largely because
of the whitespace-as-syntax thing. Again, it works for some trivial
cases, but is not general purpose enough.
So it was that I resisted bothering with Ruby for a while. "Oh," I said, "It's just another fad, like Python." But I kept hearing good things about it, even apart from all the buzz that Ruby on Rails has generated. So I finally resolved to poke at it a bit, and I'm pretty impressed. It's a much cleaner language than Perl, but it's better at functional and command-line usage than Python. It's enough to make me want to switch to Ruby for all my non-Lisp needs.
There are some things that feel like they might bother me, though. While Ruby not only supports anonymous functions but uses anonymous-function-like blocks all over the place, functions in Ruby are not first class objects, which means that you can't quite sling them around as easily as data. The use of special characters to determine variable scope (globals, class variables, instance variables, etc.) seems a bit weird to me, but at least it's not as bad as Perl's variable special characters.
Basically, Python has too much insistence on doing things its own particular, sometimes convoluted way. Ruby stole all the useful things from Perl while otherwise maintaining a very clean language that doesn't spit on my Lisp-influenced thinking.
Doing Your Own Math
When I was going to Catonsville Community College (now the Catonsville Campus of The Community College of Baltimore County), I took a couple of computer science courses. The first of those was essentially an introduction-to-programming course, with the textbook using C. The professor, however, said that he would accept programs in any language that was cleared with him beforehand. Since I already knew C, I used the class as an opportunity to learn Common Lisp.
One of the problems from the course that I still remember fondly was the "do your own math" one. We were allowed to have a function that used the language's built-in addition operator to add one to a supplied value, and the same for the subtraction operator. Building on those two functions (i.e. not using any of the language's other math operators or functions), we had to write functions to implement addition, subtraction, multiplication, division, modulus, exponentiation, greatest common divisor, and least common multiple. To simplify things, we only had to make the functions work in the domain of positive integers (so the division would be integer divisions). Because I felt like setting myself a little more of a challenge, I added a couple of my own constraints. I decided that I would make my functions work for all integers, both positive and negative, and that I would match the interfaces for the Common Lisp functions I was replacing (at least as far as integers were concerned).
I found the problem to be quite interesting because it involves breaking down common mathematical operations into their basic forms. It's also rather neat to build up a hierarchy of common routines where you've constructed each layer yourself and you end up with a tower where you've built each layer, aside from some small contributions for the foundation.
I was bored recently and decided to redo the problem, now that I've got more Common Lisp experience under my belt. In particular, I realized that I could make a new package and shadow the functions that I was replacing, so all of my code would look normal, even though I was using my own functions. I also thought it would be interesting to compare my Common Lisp programming from nearly a decade ago with my Common Lisp programming now. Here's my original code and my new code.
Probably my biggest surprise was that my original version of least common multiple gave wrong answers when supplied with multiple arguments. I clearly hadn't tested it enough in school. What's interesting is that I originally tried the same approach with my recent code, but had to fix it when I saw that it wasn't right. My recent code is also more efficient; division is orders of magnitude faster, especially for small divisors, and my old code triggers a stack overflow when asked to multiply large numbers. Structurally speaking, the newer stuff tends to be more compact; helper functions are declared with labels rather than at the toplevel, and I make better use of some Common Lisp functions, most notably reduce.
So now I've gotten even more out of the interesting problem. In addition to the fun of solving it at all, I also get a comparison of changes in my programming style over time. Perhaps I'll address it again in another decade or so.