Sat, 15 Jul 2006
Don't do This With 'find' - part 1
Hell is other peoples code. -- Not quite Sartre.
I don't mind using other peoples code. I'll even submit patches if I
find a problem, but discovering the same mistakes in almost half-a-dozen
projects is enough to drive me insane. Here are three common red flags
involving the find command and how to get around them:
If you want to be portable, don't use GNU/Linuxisms.
Compare these two commands -
find -name "*.log" # not portable
find . -name "*.log" # works everywhere
The first one works with GNU find so it's fine for (almost) all Linux distributions. It doesn't work on older Solaris, HPUX or AIX machines and saves one dot. Lesson: specify your paths.
Know what happens when you match nothing.
The first example (shown below) works fine as long as it matches. If
the find doesn't return anything you get a syntax error.
find . -name "*.tmp" | xargs rm # pray for a .tmp file
find . -name "*.tmp" | xargs -r rm
The second example exits silently if there is nothing for it to do. As
noted by Dave
Cantrell, the -r option is a GNUism so be careful where you
use it. You can also get around this by using find options -exec foo
instead of xargs. But that comes with its own baggage. Lesson: Plan for
errors.
If you're using GNU/Linuxisms then use them properly.
The GNU utilities add a number of powerful and convenient options. If you've decided that your script only cares about Linux use them and save a lot of hassle.
find . -ls | awk '{ printf("%s %s %d\n", $NF, $5, $7) }' # horrible
find . -printf "%p %u %s\n" # better
The first example is (possibly) more portable but it's horrible. And not
something you want to see in an init script. The second one is tied to
newer versions of find but is much clearer to read, once you've looked up
the escapes using man find. Lesson: Know your options.
Like this post? - Digg Me! | Add to del.icio.us! | reddit this!
Posted: 2006/07/15 12:36 | /codinghorrors | Permanent link to this entry | This entry and same date
Sat, 15 Jan 2005
Russian Roulette -- Bash Style
There are a list of things you don't want to see in your Unix machines
start up scripts but one of the leaders has to be a snippet like this:
[ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo "You live. For now."
Before we look at what the chunk of code is supposed to actually do it's worth mentioning that $RANDOM is a built-in shell variable. Each time it is read it will return a random integer between 0 and 32767. It's worth noting that although it's called $RANDOM it is no where near random enough to be used in any sensible crypto or security code / system.
Now back to the code itself, every time it runs you have a one in six chance of wiping your machine. It's not nice and once you know about $RANDOM it's not all that clever either.
Like this post? - Digg Me! | Add to del.icio.us! | reddit this!
Posted: 2005/01/15 11:40 | /codinghorrors | Permanent link to this entry | This entry and same date
Fri, 09 Jul 2004
Sed Sickness -- Whitespace Reduction
Leafing through the live source-code should be a pleasant, calming
experience, instead it often becomes a game of cringe and seek. While
digging through some custom bandwidth monitoring scripts i came across
this gem.
cat /proc/net/dev | grep eth0 | sed -e 's/:/ /g; s/ / /g; s/ / /g; s/ /
/g; s/ / /g; s/ / /g; s/ / /g; s/ / /g; s/ / /g; s/ / /g; s/ / /g;
s/ / /g;'
Working left to right we have the useless use of cat. The grep command can take a file as an argument, it doesn't need to read from standard input. This takes away one command and a | (pipe). We then move onto the bastard stepchild that is this abuse of sed. The person who wrote this is no-longer available to beat^H^H^H^H^H ask for clarification but after some head scratching it seems the author had never head of quantifiers such as + and *.
Instead it takes every instance of two spaces and makes it one space, globally. It then does it again and again until it id reduced to a single space. This is a great example for a number of reasons, wasteful repetition of code, long ugly lines and it displays a lack of knowledge of the tool. Compare the above with the following, rewritten version.
grep eth0 /proc/net/dev | sed 's/ \+/ /g'
We've killed the cat and shrunk the sed. The + is a quantifier, it changes the behaviour of the previous pattern, in this case it changes a 'match two spaces' to a 'match one space followed by any number of spaces as long as its above two.' This whole matched block is then substituted with a single space. The code is shorter, faster and easier to maintain. And it doesn't make me lose another few (precious) hairs.
Like this post? - Digg Me! | Add to del.icio.us! | reddit this!
Posted: 2004/07/09 19:20 | /codinghorrors | Permanent link to this entry | This entry and same date

