Friday, May 29, 2009

Google Runs Rings Around M$ This Week

Google seems to be in fine form this week.
  • Wednesday, they gave away Android phones to everyone at the Google I/O conference.
  • Yesterday, they announced Google Wave.
  • Today they have up the full video of the Google Wave talk. And the product will be Open Source.
And Microsoft? Their big announcement, yesterday, was bing, a new search engine to compete with Google. Which, at this point, even if it eventually works and comes out, is soooo 20th-century. Sorry.

It'll be interesting to see how Google ties this to ads.

Thursday, May 28, 2009

Editing Parallel Trees

Sometimes, I need to work in parallel trees -- trees with the same structure, but some important difference (different revision numbers, different compiler flags, ...). When I'm deep inside one tree, getting over to the homologous place in the other can be painful. Not only is it a lot of typing, but I'm often made aware that I should work at "Typos R Us."

The string substitution syntax ${FOO/bar/mumble}, which returns $FOO, but with mumble substituted for bar, solves my problem. For example, if I'm in the tree /home/jsh/tree1/a/b/c/d, and I want to pop over to /home/jsh/tree2/a/b/c/d, I just say

$ pushd ${PWD/tree1/tree2}
or even

$ cd ${PWD/1/2}
Presto! I'm there faster than you can say, "xyzzy." Or, at least as fast.

Not only am I in the new tree, but now pushd, with no arguments, (or cd - ) takes me back and forth.

Wednesday, May 27, 2009

How to Change File Extensions

Changing file extensions is easier than people make it out to be. Even on sites that provide shell programming tips, I see recipes like this:

for file in *.dat ;

do mv $file `echo $file | sed 's/\(.*\.\)dat/\1txt/'` ;

It's easier than that. Honest.
$ for file in *.dat; do mv $file ${file/.dat/.txt}; done
All in the same, parent shell. One process. No pipes, no sed, no magic regex metacharacters. So easy, you can type it on the command line.

I do it all the time.

If I need to be careful, I start like this:
      $ for file in *.dat; do echo mv $file ${file/.dat/.txt}; done
Then, if the output commands look like what I intended, I recall the loop, and tack a pipe of its output to bash on the end, like this:
      $ for file in *.dat; do echo mv $file ${file/.dat/.txt}; done | bash

Tuesday, May 12, 2009

Shell Programming Texts

There are no brief but substantial shell-programming texts.

There are two, alternative models for programming textbooks: K&R, and almost any Java book you pick up. The Java books are boat anchors. They're comprehensive, verbose, detailed, and replete with extensive terminology. K&R is brief, to-the-point.

Shell-programming books seem to follow the Java model. What would a K&R-style shell book look like?

I can't write as well as Brian Kernighan or Dennis Ritchie, but let's take a shot at a few pieces.


Unlike languages like Java or C, talking to the shell is programming in the shell. Just open a terminal window and type:

$ echo hello, world
hello, world
(Please try all the examples, even if you think you understand them. It's easy enough, so why not?)

You could type this a few times, for practice, but it's easier to recall the command than to retype it. Press the up-arrow once and you'll see the last command reappear. Press enter and the shell will execute the command.
$ ^
$ echo hello, world
The dollar sign is the prompt. It says the shell is ready to listen to your next command. Until you see the dollar sign, it's not. You can type while waiting for a prompt, and the terminal will buffer up your typing to give to the shell when it's finally done with what it's doing and ready for your next command.

A command will normally only be executed after you press ENTER, whether you've typed it or are just recalling it.
$ sleep 10
echo hello, world
[ten seconds elapses, then the next line appears, along with the execution of your command.]
$ echo hello, world
You can press the up arrow a few times to look back through your history, or you can just type the command history.
$ history
1 echo hello, world
2 echo hello, world
3 sleep 10
4 echo hello, world
(Now that you've typed it, the command history is in your history.
$ history
1 echo hello, world
2 echo hello, world
3 sleep 10
4 echo hello, world
5 history

You can refer to and re-execute a command by its history number, but we'd like to discourage that. There are more powerful ways to use history, and you should build the habit of using them from the start.

Type control-R (^R), then, slowly, "hel" and watch what happens.
(reverse-i-search)`h': history
(reverse-i-search)`he': echo hello, world
(reverse-i-search)`hel': echo hello, world
The shell is looking, in reverse, through your history to find a command that matches the string you're giving it. This is incremental search. 'h' matched "history", so that's what it found first. As soon as you typed the 'e' , it looked further and found "echo hello, world" The "l" still matched, so it didn't look for a new line.

As soon as you've found the history line you want, press ENTER to execute it.

Exercise 1-1: Search for a command that isn't in your history.

If you find yourself marooned on a line that you do not want to execute, just press ^C to cancel it and get back to a prompt. Try this both while you're typing and while you're searching through your history. Notice, by examining your history when you do this, that canceled commands don't go into your history. Only executed commands are recorded.

Friday, May 8, 2009

Mounting USB Drives Under Ubuntu

I backup daily to a USB drive, at work with git push. But the last couple of days, I've been home, sick.

I called in to ask Mike to stick in my USB drive, and he did, but it didn't automount. The automounting seems to be a Nautilus thing, and requires being logged in at the console. (I lock my screen when I leave at night.)


I made him a login, so he could get in, and that got us farther, but when it mounted, it was owned by him.

I tried mount -o remount,uid=1000, but that didn't work. The mount command showed two uid= arguments -- the first, his. (If I did it again, there were three. The first one was still his, so he still was owner.) Okay.

I jotted down the name of the device, /dev/sd1, unmounted it, and remounted it by hand, as me. Ta-da.

Tuesday, May 5, 2009

Helping My Girlfriend with Google Docs Templates

I was up past midnight beating out a first-cut resume for my girlfriend.

She's getting laid off, so she needs a new job. Her resume, built from an academic CV, is so big and impenetrable it needs to include bookmarks.

Sometimes, a job's so big that it's hard to start it yourself, so I told her I'd do it. I reasoned I could get it close enough that she could finish it up.

I started with Google Docs, which now has templates -- including, it turns out, resume templates.

A few hours playing, cutting, and pasting, and she has a first-cut that looks reasonable.

If you know someone who wants to hire a biologist, don't hesitate to post a comment.

Monday, May 4, 2009

Fixing the Default ISO App in Ubuntu Jaunty

I just changed the default application for handling .iso files under Ubuntu Jaunty Jackalope back to what it was under Intrepid Ibex. With clicky stuff.

I've been making a deliberate effort to become more comfy with GUI tools. I've been a command-line guy forever, which works fine for me, but not so well if I'm trying to help my girlfriend, or other folks who are more used to GUI, user-friendly, point-and-click interfaces.

Every Monday morning, I burn a pair of ISO images to back some stuff up to DVDs. My scripts put them onto my desktop, and I just double-click on the Destktop icons, which launches a disk-burner. (See? GUI!).

Except that this morning, I double-clicked on an iso-image icon and ... Whoops! A behavior change. It mounted the ISO.

Can I fix this by clicking? (Not "Can one?" but "Can I?")


Right click on the ISO to get a context menu. Click on "Properties," down at the bottom, then on the "Open With" tab. Sure enough, it's now set to Archive Mounter. Switch this to "Disc Burner." (And how did "disk" become "disc"? Is this a South African thing?)

Ta-da! The default for ISOs now is to burn them to disk, which is usually what I do with them.

I'm comfier with clicking all the time, which means I'm a better support guy for my friends.

Friday, May 1, 2009

Setting envelope-from on Ubuntu

After my Jaunty Jackalope upgrade, at work, some of my command-line mail tests were bouncing. Why? My sending address didn't have a Fully-Qualified Domain Name (FQDN). Some sites bounce mail that doesn't have a valid domain name in the field.

Sure enough, dnsdomainname returned ... nothing. And uname -a gave me a machine name, but not an FQDN.

I use Gmail for almost all my routine email, at home and at work. Gmail doesn't complain.

I also use command-line email in shell scripts, but that stays inside my LAN, which doesn't care about FQDNs either. I could probably have lived with the problem, but I wanted it fixed so I started poking.

I set the domain in /etc/hosts. That fixed the output of dnsdomainname,
and the From: field in the email was set correctly.

But not the mail problem. Envelope-from was still wrong. The mail to my test, outside hosts still bounced with the same complaint.

I restored the old hosts file and got Dean, our sysadmin, to give my machine a domain name through DNS. That was a little more work but it worked ... and also didn't solve the mail problem.

Finally, I stumbled over /etc/mailname. Putting an FQDN in there does the trick. The man page provides details.