That Looks Somewhat Iffy

Oh, go on, then.

  % history 1 | awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}'|sort -rn|head
  320 git
  112 ll
  80 cd
  48 ls
  24 less
  20 man
  17 sudo
  15 rm
  14 xattr


  1. This is at home, not work. At work, there’s significantly more git, ant, mvn and mate.
  2. I turn all my ssh known_hosts entries into command line aliases, hence “”.
  3. I’ve only just found xattr, so I’ve been playing with it.
  4. zsh only lists 25 history items by default. I have to ask it to start from the beginning.
  5. I obviously do too much as root.

As always, I can’t resist tinkering with the shell. I’d have written it as history 1 | awk '{print $2}' | sort | uniq -c | sort -rn | head.


Shell Scripting

I kind of like shell scripting. It’s quirky, frequently ugly, but it’s damned useful. Like Perl, it annoys me when I see things which could be written in a better manner. One persistent example is abusing the if statement.

  if [ "x$machine" = "x" ]
          echo "not in ~/.machines adding"
          echo $1 >> ~/.machines
          source ~/.bash_aliases

What’s the problem here? That little “x” in the test. It’s not necessary and hasn’t been since the late 80’s. There used to be a parsing bug in shells which meant that an empty argument got removed. So you couldn’t say [ "$machine" = "" ] because you’d end up comparing $machine to ].

But this got fixed, a long time ago. Really. Unless you’re working on an aging System III box, you shouldn’t worry about this, it’s just Cargo cult programming.

So the test can be just [ "$machine" = "" ]. That’s better. But not good enough. Testing for an empty string? The test command (aka [) provides a -z operator for that! So goes down to [ -z "$machine" ].

In this particular case, we’re explicitly targetting bash, though. One of the nice features of modern POSIX shells like bash is that they provide conditional expressions, which have different parsing rules. So you can say [[ -z $machine ]] and not worry about the lack of quotes.

Lastly, I should point out that I missed off the first line of that extract.

  machine=`grep $1 ~/.machines`

With that in place, you can see that we’re not actually using $machine anywhere in the function. It’s purely in place for the if statement. Which means you can simplify this even further. if takes a command as it’s argument. So why not just give it the grep command?

  if grep -q $1 ~/.machines
    echo "not in ~/.machines adding"
    echo $1 >> ~/.machines
    source ~/.bash_aliases

I had to add the -q flag to shut grep up; we’re only interested in the return code, not the output.

Does this matter? Probably not much. But like all programming languages, it’s a lot easier to read when you use it idiomatically.


Quote of the day

From the mod_ssl configure script:

Programming in Bourne-Shell is a higher form of masochism.

No known attribution.

This still doesn’t explain why I enjoy shell scripting so much. :-)