Basics of Perl

Variable Types

$a = 0; #scalar, used for ints, strings, floats etc.
@b = ("mon","tue","wed"); #array
%c = ('key1', 'value1', 'key2', 'value2', 'key3', 'value3'); #hash (aka associative array)

Initializing Arrays

@array = ("calvin","hobbes",1,2);

$array2[0] = "calvin";
$array2[1] = "hobbes";

@array3 = qw(calvin hobbes 1 2);

Initializing Hashes

%hash1 = ("calvin","hobbes","bill","watterson");

$hash2{"calvin"} = "hobbes";
$hash2{"bill"} = "watterson";

%hash3 = ("calvin"=>"hobbes","bill" =>"watterson")


#anonymous hashes (i.e. a reference to an anonymous hash)
$hash1 = {"calvin","hobbes","bill","watterson"};

$hash1->{"calvin"} = "hobbes"; # You can only do this once a reference has been created using the line above

Reading a File

There are two ways to read a file: using a scalar or using an array. If you use a scalar, you read in the file one line at a time. If you use an array, you read the whole file in at once.

## THE SCALAR WAY ##
open(FH,"file.txt");
while($line = <FH>)
{
# do something with each line
}
close(FH);


## THE ARRAY WAY ##
open(FH,"file.txt");
@filecontents = <FH>;
close(FH);

Reading All the Files In a Directory

opendir(DIR,"dirname") or die "Can't open dirname:$!";

while(defined($file = readdir(DIR)))
{
#do something with $file
}

closedir(DIR);

Print an Array

If you print an array the first way, all the values in the array are printed separated by a single space, like so:
calvin hobbes bill watterson

If you want to have them be separated by something else, just set the global $" variable. See the second way. Keep in mind that this is a GLOBAL variable, so unless you change it back, all your arrays are going to print with commas (unless you print them using the third way).

@array = qw(calvin hobbes bill watterson);

## FIRST WAY
print @array; # prints 'calvin hobbes bill watterson'

## SECOND WAY, PRINTS WITH COMMAS
$" = ",";
print @array; # prints 'calvin,hobbes,bill,watterson'

## SECOND WAY, IGNORES $" ENTIRELY
for $item(@array) #prints calvinhobbesbillwatterson
{
print $item;
]

Define a Function

Pay special attention to how parameters are passed in Perl.
sub function_name
{
my ($var1,$var2) = @_;
#do something with parameters
return $var1;
}


Now suppose you want to call a function like this:
makecss(cols=>4,rows=2);


How would you do it? By initializing the passed variables into a hash:
sub makecss
{
  %arg = @_;
  
  #set defaults
  $arg{cols} = 2 unless exists $arg{cols};
  $arg{rows} = 2 unless exists $arg{rows};
}


This is known as named arguments.

Iterate Over Every Element In an Array

There are two ways to doing this: the shortcut way and the more immediately understandable way. Choose with caution.

You can also use a standard for loop as shown in example three. Note how you get the final number.

## THE SHORTCUT WAY ##
# This makes use of Perl's default $_ variable.
for (@array)
{
chomp;
print;
s/a/z/gi;
}


## THE SEMI-STANDARD WAY ##
for $line(@array)
{
chomp $line;
print $line;
$line=~s/a/z/gi;
}


## THE STANDARD WAY ##
for $i(0..$#array)
{
chomp $array[$i];
print $array[$i];
$array[$i]=~s/a/z/gi;
}

Get the Length Of An Array

What are you getting the length for? There are two ways to do this, depending on what you want.

@array = qw(calvin bill watterson);

$var1 = @array; $var1 now holds 3, the length of the array.

$var2 = $#array; # var2 now holds 2, the index of the last element in the array. You can use this in for loops like for $i(0..$#array).

Splitting a String

Use the split function. The first parameter is a regex to split on. The second parameter is the string to split. Split returns an array. Here are some common uses of split:

## split a string into an array of words:
@array1 = split(/ /,$string1); #we're splitting on a space

## split a comma-separated string
@array2 = split(/,/,$string2); #we're splitting on a comma

## split a string into its characters
@array3 = split(//,$string3);

Generating a Random Number

use POSIX qw(ceil floor); # import the ceiling and floor functions

# generate a random number between 1 and 100
$num1 = floor(rand(100)+1);

#generate a random number for use with an array
$num2 = floor(rand(@array2));

Variable Scope

sub function {

  $a_global = 10; # This is a global variable
  function2(); # function2 can see $a_global because it is a global variable

}

sub function {

  local $a_local = 10; # This variable is local to this function and all function calls in this function.
  function2(); # function2 can see $a_local.

}


sub function {

  my $a_my = 10; # This variable is local to this function only
  function2(); # function2 cannot see $a_my.

}

Concatenating Strings

String a = "salman";
String b = "rushdie";
String name = a . " " . b; // Perl uses the (.) operator instead of (+)

Perl From the Command Line

The basic syntax for run a perl one-liner from the command line is:
perl [switches] -e '[your code]' [arguments]


For example, here's a script that prints "hello world!":

perl -e 'print "hello world!
";'


Switches
Here are some useful switches:
-d
Run the program using the debugger

-i[extension]
Edit files in place (if extension is supplied, perl will make a backup)

-I[directory]
Specify a directory to include in @INC.

-n
Assume a 'while(<>) { ... }' around your whole program.

-p
Like -n but adds a print; statement too.

-a
Use with -n or -p. It will automatically split input lines and place into @F.

-F/pattern/
Specify the pattern that -a uses to split on.

Find/Replace Across All Files In a Directory

perl -p -i -e 's/findthis/replacewiththis/g' *

push, pop, shift and unshift

@array = ("aditya", "bhargava", "a","b");

push @array,"c"; # @array is now ("aditya", "bhargava", "a","b","c");
$val = pop @array; # $val is "c", @array is ("aditya", "bhargava", "a","b");
unshift @array,"d"; #("d","aditya", "bhargava", "a","b");
$val = shift @array; #$val is "d",@array is ("aditya", "bhargava", "a","b");

Array Slices

#non slice way of doing things:
$array[1] = 1;
$array[2] = 4;
$array[3] = 9;
$array[4] = 16;

#with slices
@array[1,2,3,4] = (1,4,9,16);
@array[1..4] = (1,4,9,16);


#hash slices
@array{"cat","dog") = ("feline","animal");
print $array{"cat"}; # prints "feline"

Referencing and Dereferencing

To create a reference to a variable, put a in front of a variable. To dereference a variable, put a $ in front of the reference. For example:

$b=0; $a = $b; $$a++;
print "$b "; # prints 1


Referencing:
Here's some examples of references:
$ref = $s; # $ref is a reference to a scalar
$ref = @s; # $ref is a reference to an array
$ref = \%s; # $ref is a reference to a hash
$ref = &s; # $ref is a reference to a function / subroutine


Dereferencing:
Example:
print $ref; #prints something like SCALAR(0x1800e98) if it's pointing to a scalar
print $$ref; # prints the value of the scalar it's pointing to


Array example:
print ${$arr_ref}[0]; # prints the first element of whatever array $arr_ref points to


Arrays and hashes are easier to defererence with the arrow operator:
print $arr_ref->[0]; # same thing as above

Create a Two-Dimensional Array

Ordinarily, you have to make a two dimensional array by stuffing references to arrays inside another array, like this:
@row1 = qq(1 2 3);
@row2 = qq(4 5 6);
@row3 = qq(10 11 12);

@rows = qq(@row1 @row2 @row3);

And then you have to do this to access them:
print $rows[0]->[1];


You can do this instead:
$rows = [
[1,2,3],
[4,5,6],
[10,11,12],
];

print $rows->[0][1];


And that magically creates a 2-d array for you. Also note that:
# You can write this:
print $rows[0][1];

# instead of this:
print $rows[0]->[1];

Packages

Packages create namespaces. You can't have multiple variables called $a in a program:
$a = 1;
$a = 2;
$a = 3; ## these are all the same variable.


Unless you have them in different packages:
$a = 1;

package Another;
$a = 2;

package AndAnother;
$a = 3;

Now Perl will choose the correct $a depending on what package you're in:
print $a; # defaults to main package, prints 1

package AndAnother;
print $a; # prints 3

package Another;
print $a # prints 2

print AndAnother::$a; # prints 3
print main::$a; prints 1


Package names can have multiple parts, separated by a double colon:
package Another::Package;


Just because package Another and Another::Package have the same initial part, it doesn't mean that there is any connection between them. Another::Package is not connected with Another in any way.

Create a New Module

Where to put a module
View the contents of @INC with:
print "@INC";

Any of the paths indicated there is where you can put your module. To add a new path:
Permanently add a new path
In Terminal, type:
export PERL5LIB="${PERL5LIB}:/your/new/path"

Temporarily add a new path
In your Perl script, type:
use lib "your/new/path";
BEGIN{ # ANOTHER WAY TO DO IT.
push @INC, "your/new/path";
}


Create the appropriate directory structure for your module
If you module is called 'X', you can save it right in one of the directories we discussed above. If it's called X::Y::Z, then you need to create a new folder X, and inside it a new folder Y, and in that, place Z.pm.

A module template
package X::Y::Z; # give the package it's own namespace
require Exporter; #this is what makes it possible to automatically export symbols (functions, variables etc)

our @ISA = qw(Exporter);   # Inheritance in perl
our @EXPORT = qw();        # Symbols to be exported by default
our @EXPORT_OK = qw();    # Symbols to be exported on request
our $VERSION = 1.00;      # Version Number


## Include your variables or functions here



# A use statement evals the contents of a file. The last expression in the file must evaluate to true, or the eval dies. It is conventional to end .pm and .pl files with a 1 to provide this value.
1;

Autoloading

In most programming languages, if you call a function that doesn't exist, you get an immediate error. In Perl, you can create a catch-all function for each package, that will run if someone calls a function that doesn't exist. This is called Autoloading.
To use it, just define a function AUTOLOAD:
sub AUTOLOAD
{
# put default code here.
}


AUTOLOAD gets the parameter list that was intended for the missing function. Perl also sets a variable $AUTOLOAD to the name of the function that someone had tried to call. So you could politely inform them that that function doesn't exist like so:


sub AUTOLOAD
{
print "Sorry, $AUTOLOAD is not defined. ";
}

Destructors

To create a destructor for a class, just create a function called "DESTROY":
sub DESTROY {...}


It will be run automatically right before the object is destroyed.

Edit An Installed Module

There are several reasons to edit an installed module:
- You're curious to see how it was implemented
- You've found a bug and you want to fix it
- You want to inherit from it

Or you just want to learn Perl. Examining top-notch modules are a good way to see how Perl experts write code. To edit a module, type this in your Terminal:
perldoc -l [modulename]


This will tell you where the .pm file for the module is located. It will return something like
/opt/local/lib/perl5/site_perl/5.8.9/PAR.pm


To open this file, just type
open [path to file] # opens in your favorite text editor
pico [path to file] # opens in pico
vi   [path to file] # opens in vi
emacs [path to file] # opens in emacs

Encoding / Decoding Using Storable

aka Serializing / Deserializing
Encoding:
use Storable;
$a = 250;
store $a,"test.dt"; # passing a reference to the variable


Decoding:
use Storable;
$a = retrieve "test.dt";
$a = $$a; # get the actual value from the reference

Encoding / Decoding Using FreezeThaw

We're saving to a file, but you can use this while writing to a database instead (see below). Using FreezeThaw ensures that interrelationships between variables are saved.

Encode:
use FreezeThaw qw(freeze thaw);
$two = "200";
$enc = freeze ($two);
open (FILE,">test.dt") and print FILE $enc and close(FILE) or die "$!";


Decode:
use FreezeThaw qw(freeze thaw);
open (FILE,">test.dt") and @enc= or die "$!";
@arr = thaw (@enc);
(*one) = @arr;

Encoding / Decoding Using Data::Dumper

The unique thing about Data::Dumper is it saves the data as a Perl script. So all you need to do for decoding is eval the script, and you're good to go.

Encoding:
use Data::Dumper;
$input = "adit";
$enc = Data::Dumper->Dump([ $input],["input"]);
open (FILE,">test.dt") and print FILE $enc and close(FILE) or die "$!";


Decoding:
do "test.dt";

Encoding / Decoding Using DB_File

DB_Files allows you to tie a hash to a database. After that, all reads / writes to the hash will read / write to the database.
The "O_CREAT | O_RDWR" line tells Perl to create the database if it doesn't exist and give us read/write access.
If Perl has to create the database, it will be create with permissions set to 640 as specified.
$DB_HASH is a variable exported by Fcntl for use with DB_File.

Encoding:
use DB_File;
use Fcntl;
tie %a, "DB_File","persistent.db",O_CREAT | O_RDWR, 0640, $DB_HASH;
# you could write the above line like this too:
# tie %a,"DB_File","persistent.db";
$a{'adit'} = "bhargava";
$a{'dennis'} = "mitchell";


Decoding:
tie %a, "DB_File","persistent.db";
print $a{'adit'},"
";

Catching Interrupt Signals

An interrupt signal is when someone presses Ctrl-C in the middle of your program to terminate it. Sometimes you want to catch this signal — if you intend to save out to a file at the end of your program, for example. To catch an interrupt signal, set the $SIG{'INT'} variable:

BEGIN { # need to put this in a BEGIN block if we want it to be set in time.
  $SIG{'INT'} = sub {print "thanks for playing."; exit;};
}


In the anonymous subroutine, you can do whatever you want. Just make sure you put 'exit' in there somewhere, or else your program will not quit when someone presses Ctrl-C.

Run Some Code Right At The Start Of Your Script

To run something before anything else in your script, use a BEGIN block:
BEGIN{
push(@INC, '/some/path/'); # A common use for a BEGIN block
}

Run Some Code At The Very End Of Your Script

Put it in a END block:
END{
# do something (like save your data)
}

If you want this code to run even if someone presses Ctrl-C to terminate your application, you need to catch the interrupt signal and tell it to run the END block before exiting. Here's how you do it:
$SIG{'INT'} = sub { exit(0); };

Search For Something In Perldoc

perldoc -f [something] // search functions
perldoc -q [something] // search faq

Sorting

@a = {1,2,3};
sort @a; # default sort

# custom sort
@sorted_lines = sort{$b->frequency() <=> $a->frequency()} @a; # $a and $b are elements in the array. The function should return -1 if $a should go before $b, 0 if it doesn't matter, or 1 of $b should go before $a.

Install a New Module

sudo cpan [module name]

Command Line Arguments

All command line arguments are in the array @ARGV. The are accessed individually using $ARGV[0], $ARGV[1] etc.

Convert A Number To A Character And Vice-Versa

Use chr and ord

$v = ord("A"); # $v now holds '65'
$alpha = chr(65); $ $alpha now holds 'A'

Here Documents (heredocs)

print <<END;
some bunch
of text
here
END

Getting The Size Of An Image Using ImageMagick

use Image::Magick;      
my $image = Image::Magick->new;
$image->Read("test.jpg");
my $img_width = $image->Get('columns');
$img_height = $image->Get('rows');

Posterize An Image Using ImageMagick

use Image::Magick;      
my $image = Image::Magick->new;
$image->Read("test.jpg");
$img_open = $image->Posterize('4');
$img_open = $image->Write("test_posterized.jpg");

Resize An Image Using ImageMagick

ImageMagick will automatically preserve the width and height proportions and will resize the image so it's as large as possible while not being larger than the specified dimensions.

use Image::Magick;      
my $image = Image::Magick->new;
$image->Read("test.jpg");
$img_open = $image->Resize(geometry=>'200x200');
$img_open = $image->Write("test_resized.jpg");

Crop An Image Using ImageMagick

The format for the geometry is:
[width]x[height]+[x]+[y]

use Image::Magick;      
my $image = Image::Magick->new;
$image->Read("test.jpg");
$img_open = $image->Crop(geometry=>'100x100+0+0');
$img_open = $image->Write("test_cropped.jpg");

Blur An Image Using ImageMagick

use Image::Magick;      
my $image = Image::Magick->new;
$image->Read("test.jpg");
$img_open = $image->Blur(100);
$img_open = $image->Write("test_blurred.jpg");

Bitwise operators

Shift Left

This is like multiplying a number by two:
110 -> 1100.

$input = 50;
$input = $input << 1;
print "$input"; # prints 100.


Shift Right

This is like dividing a number by two:
110 -> 011.

$input = 50;
$input = $input >> 1;
print "$input"; # prints 25.

Substrings

The general format is:
$fragment = substr $string, [start at], [end at]

Example:

$string = "aditya";
$fragment = substr($string,1); # $fragment is now 'ditya'
$fragment = substr($string,1,1); # $fragment is now 'd'
$fragment = substr($string,1,2); # $fragment is now 'di'
$fragment = substr($string,1,4); # $fragment is now 'dity'

# negatives
$fragment = substr($string,-2); # $fragment is now 'ya'
$fragment = substr($string,-2,1); # $fragment is now 'y'

Change Working Directory

# same as C:
chdir "path/to/some/directory";

Convert Hex Number To Decimal

hex([some hex number]);

Convert Decimal Number To Hex

$somestring = sprintf("%x",[decimal number]);

One's Complement

A one's complement basically just reverses all the bits, so
11110101 becomes
00001010

etc.

Here's an example:

print ~1; # prints 4294967294


This prints 4294967294 because 1 in binary on a 32-bit computer is actually
00000000000000000000000000000001 <--- 32 bits

so the one's complement is
11111111111111111111111111111110

which is 4294967294

Last Matched String

$&