Friday, April 20, 2007

A Better Shell

The product I'm helping to develop at work has a TCP service that you can telnet to and get a simple command-line shell for development purposes. In our firmware we have a simple framework for writing commands that can then be called from this shell. You can do all sorts of handy things like check sensors, run calibrations, query ASIC registers, read and write memory locations, and so forth. We also use this to play with different configurations and new features before making them permanent. The big downside to this shell is that, well, let's just say that for anyone used to a modern shell like bash, this one is stone-age. There is no command history, no command-line editing except to backspace and retype, and no scripting. This can get very frustrating when you have a command or set of commands that you need to run over and over. Especially when you start using fairly complicated ones with hexadecimal memory addresses, bit masks, and other esoteric parameters. Sure, somebody on our firmware team could add these features to our shell, but who has time for that (when we could be blogging instead, right?)?

I have been bringing up some new hardware for the past few weeks and using this shell heavily for that task. After the EEs I'm working with and I lamented for about the 100th time the lack of at least a history feature, the solution finally came to me. It was like Obi-Wan Kenobi whispered to me, "Bryan, use the emacs." I turned off my targeting computer my gnome-terminal that was running telnet and moused over to emacs (it's always running).

"Bryan, what's wrong?" my EE partner worriedly inquired. I typed M-x shell and then telneted to the appropriate port. I typed a command. It worked. I hit M-p and the command I'd just used magically appeared at the prompt, ready for action a second time. A chorus of angels sang. I edited the parameters of the command before sending it, using all the familiar emacs shortcuts. The angels' song rose in pitch. My partner's mouth hung open. After typing a few different commands, multiple M-p's scrolled through all the past commands. A C-r began a search through the buffer history so I could quickly get to a past command I wanted, and macros and elisp were now at our disposal for scripting it. Our simple shell just got a whole lot more features.

There is really only one problem with this that I've discovered. Most of the commands we use echo any output to our serial console, but some echo back to the shell. Some of the output that goes back to the shell doesn't show up in emacs for some reason. If anyone has any tips on that one, please let me know.

Oh, and, uh, sorry for getting a little over dramatic there. I'll try to tone it down next time emacs causes me to weep with joy (dang, there I go again).


Anonymous said...

Another solution if you don't want the whole emacs hog (sacrilege!) is the readline wrapper rlwrap

Anonymous said...

Emacs also has a telnet mode; M-x telnet RET. Many other common UNIX utilities work this way, too, e.g. M-x ftp, M-x ping, M-x traceroute, etc. See net-utils.el and telnet.el.