Monday, October 26, 2009

Small and cute shell and Perl scriptlets

Once upon a time, the world was full of small and cute shell and Perl scripts that served a small but useful purpose, and which were shared freely - just because hackers were nice guys. So we bring some of these around with us, in slightly modified or improved versions.

I'd like to carry on the tradition of sharing some of these before they are lost, even though they are about as trivial as you can get.

Eval

Here's one that I picked up at the University of Oslo 10-15 years ago, which I still use, just out of habit. The file is traditionally named Eval, and I believe this particular version was concocted by Kjetil T. Homme (who has some other nice hacks, BTW). The idea is to have an easy-to-use command line calculator:
#! /bin/sh -

exec perl -e '$a = ('"$*"');
if ($a == int($a)) {
print $a, "\n";
} else {
printf ("%.3f\n", $a);
}'
So what's the point?

For me, it's the ease of use, and not least the ease of installability. All I need is a Perl version that understands a very simple set of commands. I don't have to worry whether bc or dc is installed, I don't have to open a GUI, and I can work with fairly advanced expressions. They just have end up as valid Perl.

7

Did you ever forget exactly which octal code to use for the ASCII letter 'h', or the hex number for the backtick (`) character? 7 to the rescue!
#! /usr/bin/perl -C

for (32..126) {
printf "%3d 0x%02X 0%03o 0b%08b %c\n", ($_)x5;
}
And if you still haven't made the transition to Unicode/UTF-8, printing the printables in e.g. a Latin character set may still be interesting; create a copy of the file called 8, which works on the range 160..255 instead. Or be fancy with basename checking and all that. :)

Answer

When I write scripts that do potentially Dangerous Stuff on production servers (that happens way too often), I usually like to include some code that tells the user to think a bit before continuing. That is, I don't want all scripts to be fire-and-forget. This is another classical piece of code, which I've massaged for my own needs (and perhaps your needs as well?):
print "About to run $code.\n\n";
print "Are you sure? (y/N): ";
my $answer = <STDIN>;
chop $answer;
if ($answer !~ /^y(es)?$/i) {
die "Okay, aborting.\n";
} else {
print "Okay, continuing!\n";
}

Monday, October 19, 2009

183 days of Iron Man blogging

Today it's 183 days - more than half a year - since I started blogging, spurred on by mst's lightning talk at NPW 2009.

That ain't half bad.

But he's still not losing his bet yet, argh! :D

Coding styles that make me twitch, part 5

Let us say that we have some code using DBI - old-fashioned, but it still works, kindof.

How would you like to see the following in a 6000 line CGI script you're supposed to debug?

my $sth=&query("SELECT id FROM invoices WHERE invoiced='N'");
my $invoiced=$sth->rows;

my $sth2=&query("SELECT count(*) nusers FROM users \
LEFT JOIN people ... # long SQL statement
my $row2 = $sth2->fetchrow_hashref;
my $nusers = $row2->{nusers};

my $sth3=&query("SELECT count(*) npeople FROM users \
LEFT JOIN people ... # long SQL statement
my $row3 = $sth3->fetchrow_hashref;
my $npeople = $row3->{npeople};

my $sth4=...
And then, after carefully checking scope, you discover that the variables $sth2, $row2, $sth3, $row3, $sth4, $row4 etc. are not used anywhere else within the same scope.

Would you develop a tick?

I did, and the tick didn't lessen in strength when I discovered unsafe variable interpolation as well as a sub query that used $dbh->prepare($qtext) but didn't allow passing of usable parameters, such as, you know, bind variables.

I've started on "refactoring" the real life code this example is based on, but I get depressed from the sheer amount of work in fixing many problems at once. Maybe I should pick up drunken coding to become less perfectionist.