Tuning Into Ten Short, Useful Perl Programs - dummies

Tuning Into Ten Short, Useful Perl Programs

By Paul Hoffman

Some people believe that short programs aren’t good for very much, but that’s not so with Perl. Just a couple lines of Perl code can go a long way. This article lists some handy teeny, tiny Perl programs.

Collecting unique lines

If your text file has many lines that are duplicates and you only want to see the unique lines, you can collect them into an array (in this case, it’s called @Unique) with the following program:

open(IN, “somefile.txt”); @Unique=();
while(<IN>) { unless($i{$_}++) { push(@Unique, $_) } }

The trick here is that $i{$_}++ returns 0 the first time you create a key-value pair with $_ as the key, and some nonzero value after that.

Getting rid of multiple blank lines

Some text files have multiple, consecutive blank lines, which make them hard to read, particularly on small screens. The following program prints a text file, compressing all instances of two or more blank lines into a single blank line.

Note: A blank line can have whitespace characters in it, such as spaces and tabs, but no displayable characters.

open(IN, “somefile.txt”); $PrevBlank = 0;
while(<IN>) {
if(/S/ or !$PrevBlank) { print $_ }
$PrevBlank = /^s*$/;

The if statement in the preceding example is true if there are nonblank characters on the line or if the previous line was not blank. The $PrevBlank assignment tells you whether the current line is blank, meaning that it has zero or more whitespace characters and nothing else.

Printing lines from a file in sorted order

It’s easy to forget how useful Perl’s sort function is. The following program reads the entire file into an array, sorts the array, and prints the result. Short and sweet, and pretty efficient to boot:

open(IN, “somefile.txt”);
print sort(<IN>);

Printing a range of lines from a file

Have you ever wanted to read just a few lines from a file, and not the whole thing? The following program prints just a range of lines. You run the program with two arguments: the range you want and the filename. For example, if you name your program “showline” and you want to see lines 10 through 20 of the somefile.txt file, you use this command line:

showline 10-20 somefile.txt

The following program prints a range of lines:

open(IN, $ARGV[1]) or die “Could not read $File.n”;
($Start, $Stop) = split(/-/, $ARGV[0]);
for($i=1; $i<=$Stop; $i += 1)
{ $Line = <IN>; if($i>=$Start) { print $Line } }

Listing just the files in a directory

At times, you may want to ignore the subdirectories in a directory and just focus on the files. You can use the following -f file test to list all the files in a directory:

foreach $f (<*>) { if(-f $f) { print “$fn” } }

Listing a directory by size

To sort, a directory listing by anything other than its filenames, your program has to keep a list of records consisting of the names and other items in the listing. Hashes are great to use for this kind of list that has records with a key (the filename) and a value (the other directory information). The following program creates a hash that lists the size of each file in the directory and then sorts the items for output. (You can easily modify this program to sort by date instead of by size.)

foreach $f (<*>) { $i{$f} = -s $f };
foreach $k (sort{ $i{$b} <=&gt $i{$a} } keys %i)
{ printf “%8d %sn”, $i{$k}, $k }

Sorting directories by extension

Sorting by a portion of a filename is a slightly more difficult process than sorting by file size or by the date the file was modified. The following program breaks the filename into two and sorts by the second part. If you’re running Perl on a UNIX or Macintosh system, this program works predictably only if the filenames have no period or one period:

foreach $FullName (<*>) {
($Name, $Ext) = split(/./, $FullName, 2);
push(@Temp, “$Extt$FullName”);
foreach $Val (sort(@Temp)) {
($Ext, $FullName) = split(/t/, $Val);
print “$FullNamen”;

Creating a simple calculator

Ever needed a simple-to-use calculator to knock off some quick-and-dirty math? The following program uses Perl’s eval function to print out the answers to any equation you enter. To end the program, enter a blank line. Here’s that program for creating your own calculator:

while(<STDIN>) {
$i = $_; chomp($i); unless($i) { last }
$o = eval($i); print “Answer = $on”;

When you run the program, you can enter something like the following:

((2**8) + (3**8))

and you get this result:

Answer = 6817

Randomizing a list

In Perl, generating random numbers is easy, but randomizing the order of an array isn’t as simple. Nevertheless, you can use the splice function to pull a random element from an array and then place the element in another array. The following program randomizes the list @MyList:

my @TempList = ();
{ push(@TempList, splice(@MyList, rand(@MyList), 1)) }
@MyList = @TempList;

The trick here is that rand(@MyList) picks a number between 0 and the number of elements in @MyList, and splice changes this random number to an integer.

Generating random mnemonic passwords

Trying to convince computer users to come up with passwords that aren’t easily guessed is one of the most challenging jobs for a system administrator. People always seem to insist on using their birthdates or pets’ names for passwords — breaching security then becomes child’s play.

The following program generates random passwords. Instead of a jumble of hard-to-remember letters, however, the passwords are somewhat mnemonic because they appear in pairs of consonants and vowels that are pronounceable. By stringing together a few goofy-sounding syllables, you can generate easy-to-remember nonsense phrases.

Each syllable of the password can represent any one of 100 numbers; therefore, a single four-syllable password, such as votahubo, is one of 100 million (100 to the fourth power) possible passwords the program generates. Having a system administrator assign these passwords provides more security than letting users pick their own, easily guessed passwords:

print “Enter a seed number: “; $s=<STDIN>;
srand($s ^ time);
@c=split(/ */, “bcdfghjklmnprstvwxyz”);
@v=split(/ */, “aeiou”);
for($i = 1; $i <=4; $i += 1)
{ print $c[int(rand(20))], $v[int(rand(5))] }

The first two lines of this program initialize the seed for the random numbers, and the next two lines create lists containing the 20 consonants (minus q) and 5 vowels of the alphabet. The for loop simply prints the four syllables.