perl


perl is a handy language that's more powerful than shell programming, but less formal and time-consuming than C++.   It uses the same ideas of metacharacters and regular expressions that are used by grep, awk, and sed.   (For more about metacharacters, see my sed webpage.)

Example 1: cosmic.pl
This script looks in a C++ header file for a marker string, which is supplied at the command line; (it takes the following forms: "sk1marker" "sk2marker" "sk3marker".)   Then the script finds the line containing the input string and deletes everything that is not a number or a space from that line.   Then it deletes leading space.   The split function takes a string as its first argument (" ") and a regular expression ($_) as its second argument.   It returns a list of values from the regular expression that are separated by the a space, which in this case, correspond to three numbers.   Like C, the array/list is numbered beginning with 0.   Last, the program adds the (three) numbers and prints their sum to the standard output.
#! /usr/bin/perl
#syntax: cosmic.pl skxmarker cosmic.h
$input = shift;
while (<>) {
    if (/$input/) {
        s/[^0-9 ]//g;
        s/^ *//;
        @nums = split (/ /,$_);
        $answer = $nums[0] + $nums[1] + $nums[2];
        print $answer
    }
}
To define an array (w/o using split): @p3 = (46,78,67);
To define a multidimensional array: @test = ( [1,2], [3,4], [5,6] );
To define an array of arrays:
@t1 = (1,2);
@t2 = (3,4);
@test = (\@t1, \@t2);

Example 2: scramble.pl
This script reads in a file and spits out the lines in a random order.   Notice, that $#ARGV+1 is the equivalent of argc in C++.   Also notice that it goes down by one value, when you shift perform the shift command.   The dot operators concatenate strings.   The int() function converts floats to integers.
#! /usr/bin/perl
if($#ARGV+1 ==0 ) {print "syntax: scramble.pl filename outlines\n"; exit;}
$filename = shift;
$outlines = shift;
$nlines = `~ethrane/bin/lc.csh $filename`;
if($outlines > $nlines) {print "outlines > nlines\n"; exit;}

$x = 0;
while ($x < $nlines) {$array[$x] = 0; $x++;}

$x = 0;
while ($x < $outlines) {
    $ok = 0;
    $l = int(rand($nlines))+1;
    while ($ok == 0) { 
        if($array[$l] == 0) {
            $ok=1; $array[$l]=1;
            open(file, $filename);
            while() {if($.==$l) {print $_;}}
            close(file);
        }
        $l++; if($l > $nlines) {$l += -$nlines;}
    }
    $x++;
}
Example 3: qclean.pl
This script sleeps for 10 seconds, then erases .log and .err files from a batch NQS submission before going back to sleep.   It runs for 3 hours or until NQS is idle.

To execute unix commands from within a perl script: system "ls";
To kill UNIX jobs:
# kill all open pine sessions
system 'killall', 'pine';

# open a new pine session
system "pine";
To set perl variables using unix commands: $test = `ls`;

Example 4: math.pl
Looks for the regular expression "Out.*" (from the Mathematica kernel.)   Deletes all other lines and converts output into C++ style scientific notation.
#! /usr/bin/perl

while (<>) {
    if(/Out.*/){
        s/Out\[.*\]= //;
        s/ 10\n//;
        print ($_,"E",$exp);
    }
    s/ *//;
    $exp = $_;
}
Example 5: RunTheta.pl
In this example, we use a foreach loop to loop over muon energies.   We use the commands open and close to read an input file and write to an output file.

To open an input file:
open(input, "./input.dat");
#multiply each line by 3 and print the result.
while (<input>) {print $_*3;}
close(input);
To open an output file:
open(output, ">>./output.dat");
print output ($x,"\n");
close(output);

Example 6: Part2.pl
Loop over files that end in ".dat" with a foreach loop.   Use the command chomp to remove a trailing line break.

To loop over files in the directory "tmp/" that end in ".dat": foreach $file (<./tmp/*.dat>) { ... }
Another way to examine the contents of a directory:
opendir(DIR, "./tmp");
@list = readdir(DIR);
closedir(DIR);
foreach $file (@list) { ... }
Does a directory exist? if (-d $dirname) { ...
To delete the trailing line break from the variable $x: chomp($x);

Example 7: sort_bib.pl
Change the order of entries in a bibtex file so that the last entries come first and the first entries come last.
#! /usr/bin/perl5.30

$i = -1;
while (<>) {
    # if the line defines a shortcut (string), it is not a bibtex entry
    if ($_ =~ m/\@String.*/) {print "$_";}
    # if the line begins with % it is a comment, not a bibtex entry
    elsif ($_ =~ /\%.*/) {print $_;}
    # skip over white space
    elsif (/^\s*$/) {}
    else {
    # bibtex entries begin with @
    if ($_ =~ m/\@.*/) {
        $i++;
        $entries[$i] = $_;
    }
    # still part of the same bibtex entry
    else {
        $entries[$i] = $entries[$i].$_;
    }
    }
}

# create extra space between strings and bib entries
print "\n";

# print entries in reverse order
for ($j=$i; $j>=0; $j--) {
    print $entries[$j]."\n";
}

# print bib entries in order with numbers (testing only)
#for ($j=0; $j<=$i; $j++) {
#    print "########### $j ###########\n";
#    print $entries[$j];
#}
Example 8: Prepare a bib entry for upload to RMS: sort_bib_arc.pl.

To substitute/replace a string in a perl variable:
$x = "The height is zpos.\n"
$x =~ s/zpos/-100/;
print $x;
The height is -100.

To access UNIX environmental variables from Perl: $out = "$ENV{'workdir'}";
To test if a variable contains a certain regular expression: if($varb =~ m/[0-9]\.5/) {print $varb;} ("m" is for "match.")
The line number in the current open file: $.
or alternatively:
open $fh, "findjobs.out";
my @lines = <$fh>;
print "$lines[3]"
To create a sub-function:
sub short {
    $_[0] = int($_[0])."."    #$_[0] is the 0th argument of short().
} 
To use a trigonmetric function:
use Math::Trig;
print acos(-1);
a for loop: for ($i=0; $i<12; $i++) {$dtheta += rand();}

To compare the values of two strings: if($table eq "swift_grb_table.dat")

To remove extra white space: $_ =~ s/\s+/ /g;
To remove ^M characters created by Microsoft Excel: $_ =~ s/\015/\n/g;

To open two input files at once:
open(input1, "input1.dat");
while($x=<input1>){
      open(input2, "input2.dat");
      while($y=<input2>){
      ...
or better yet: while ($q=<file>,$n=<nfile>) {
To call perl from within a csh script:
setenv fres `perl -e '{  \
  $fres = sqrt(13);\
  print $fres;\
}'`
To access environmental variables in perl: $x = $ENV{'PATH'};

sort: @sorted = sort @array;
array size: $size = $#array;

numerical precision: $x==sprintf("%.3f",$x);

open two files at once: open(trial100, "./trial100.list");
open(tmp,">tmp.txt");
while($x = ){ # $x is like $_


Back to Resources