[TriLUG] bash scripting - formatting and verifying input

Kevin Hunter hunteke at earlham.edu
Thu Feb 28 21:10:18 EST 2008


At 7:17p -0500 on Fri, 29 Feb 2008, Jeremy Portzer wrote:
>> if ( $IPADDR =~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ ) {
>> 	...
> 
> Here's a question/challenge - how would you modify this to verify
> that each octet is between zero and 255?
> 
> You can't just make sure that the first digit is a 1 or 2, because
> that would prevent ".95" from matching.
> 
> My approach would probably be to use Perl's "split" function to
> separate the octets into individual variables, and then check each
> one with integer comparisons.  But I'd be interested to know if
> there's a way to do it within a regexp.

Without offending any of the real Perl guru's on this list, I'll say
yes, it's possible, but I would *not* do it in my code. Perl's motto is
something like "There's always another way to do it," but I don't think
that should mean that everyone should find their own individual method.
This is one reason Perl has a reputation for producing ugly/unreadable
code.  Without going on a rant that code should be written for *humans*
to read (not the side-effect that makes computers do what we want), I'd
sum this up with a "use the right tool for the job," and don't turn all
jobs into a proverbial nail.

Thus, one approach would be to use a simple regex as above (because it's
human readable), perhaps capturing each of the octets in the process,
then compare individually.  This has the benefit that though it
may not be the most computer-efficient, it is damned easy for any
half-way competent programmer to read.  (Whose time are you optimizing
for, anyway?!)  It also lends itself to global definitions, such as if
the job in question needs a dynamic IP comparison range (command line
arguments, anyone?).

However, if you're still bent on solving it via the regex itself, there
are a few of ways.  Of the top of my head, you could code for each of
the possibilities as:

$oRegex = '\d{1,2}|1\d{2}|2(?:[1234]\d|5[12345])'; # octet regex
if ( $IP !~ m/^($oRegex)\.($oRegex)\.($oRegex)\.($oRegex)$/ ) {
	die( "Silly Rabbit: Tricks are for crackers! (Bad IP: $IP)\n" );
}

If you really wanted to get nasty, you could embed Perl code in the
regex itself.  Having only had to do this a couple times, I won't delve
into it here, but the syntax for which you're looking is (${ code }).

That all said though, let me reiterate that at the point you're trying
to solve logic problems with a matching tool, 98% of the time you
should stand back and rethink what your doing.  Pick the right tool for
the job at hand.  If you are a programmer of any intelligence, you
should have a few.

Kevin



More information about the TriLUG mailing list