Friday, February 29, 2008

Using $PATH

Linux, like Unix, finds commands by searching $PATH.

A disadvantage of this is that I have to ask where a command is. The classic
$ /usr/bin/which rm_bad_symlinks
/home/jsh/rm_bad_symlinks
works, but requires forking a new process.

The builtin type is faster, but the syntax of the returned answer is awkward.
$ type rm_bad_symlinks
rm_bad_symlinks is /home/jsh/bin/rm_bad_symlinks
And type --path does what I want, but it's awkward to type. I step around the problem with an alias:
$ alias which='type --path'
$ which rm_bad_symlinks
/home/jsh/rm_bad_symlinks
The difference in real cost, on a single-user machine, is completely inconsequential, yet because I feel like it's near-free, I use it all the time.
$ cat $(which rm_bad_simlinks)
#!/bin/bash
# $Id: rm_bad_symlinks 363 2007-06-01 14:30:50Z jsh $
file * | perl -F: -lane 'unlink $F[0] if /broken symbolic link/'
$ vi $(which rm_bad_symlinks)
...
and so on.

This is me fooling myself. I'm calling which in a subshell, so it's actually invoking /usr/bin/which (Aliases are strictly interactive, and confined to the current shell.)

Yet, it changes how I behave. Go figure.

On the opposite side of the coin, $PATH lets me write cleaner scripts, because I can say exactly where I'm taking commands from without jumping through hoops.

I read through a longish script yesterday, in which the first half of the script parameterized command names, and the second half used those parameters.
MOVE=/bin/mv
LINK=/bin/ln
COPY=/bin/cp
...
${MOVE} foo.conf /etc
...
and so on.

(This kind of thing was arguably useful in the old days, when different vendors would install standard programs in idiosyncratic places, but the LSB has done away with most of that.)

Here's how I'd write it:
export PATH=/bin:/usr/bin
mv foo.conf /etc
It's easier to read and much shorter, but still just as safe and just as correct.

No comments: