$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)
@array = ("calvin","hobbes",1,2);
$array2[0] = "calvin";
$array2[1] = "hobbes";
@array3 = qw(calvin hobbes 1 2);
%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
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);
opendir(DIR,"dirname") or die "Can't open dirname:$!";
while(defined($file = readdir(DIR)))
{
#do something with $file
}
closedir(DIR);
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;
]
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.
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;
}
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).
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);
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));
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.
}
String a = "salman";
String b = "rushdie";
String name = a . " " . b; // Perl uses the (.) operator instead of (+)
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.
perl -p -i -e 's/findthis/replacewiththis/g' *
@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");
#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"
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
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 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.
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;
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.
";
}
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.
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
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
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=
@arr = thaw (@enc);
(*one) = @arr;
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";
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'},"
";
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.
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
}
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); };
perldoc -f [something] // search functions
perldoc -q [something] // search faq
@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.
sudo cpan [module name]
All command line arguments are in the array @ARGV. The are accessed individually using $ARGV[0], $ARGV[1] etc.
Use chr and ord
$v = ord("A"); # $v now holds '65'
$alpha = chr(65); $ $alpha now holds 'A'
print <<END;
some bunch
of text
here
END
use Image::Magick;
my $image = Image::Magick->new;
$image->Read("test.jpg");
my $img_width = $image->Get('columns');
$img_height = $image->Get('rows');
use Image::Magick;
my $image = Image::Magick->new;
$image->Read("test.jpg");
$img_open = $image->Posterize('4');
$img_open = $image->Write("test_posterized.jpg");
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");
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");
use Image::Magick;
my $image = Image::Magick->new;
$image->Read("test.jpg");
$img_open = $image->Blur(100);
$img_open = $image->Write("test_blurred.jpg");
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.
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'
# same as C:
chdir "path/to/some/directory";
hex([some hex number]);
$somestring = sprintf("%x",[decimal number]);
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
$&