Tutorial On Perl Basics: Practical Extraction and Report Language
Tutorial On Perl Basics: Practical Extraction and Report Language
Tutorial On Perl Basics: Practical Extraction and Report Language
PracticalExtractionandReportLanguage
By
SritharDurairajIBMIndia
Introduction
WhatisPerl?
Perlisaprogramminglanguage.PerlstandsforPracticalExtraction
andReportLanguage.Itisainterpreterlanguage.Itisallaboutsmall,
quickprogramsandlooselytypedlanguage.VersionsofPerlpriorto
5areveryoldandveryunsupported.
Speedofdevelopment
Editatextfile,andjustrunit.Noseparatecompilerneeded.
Power
Regularexpression.objects,sockets...everythingasystems
administratorcouldwant.Addthewealthofmodulesavailable
onCPAN(www.cpan.org)
Usability&Portability
PerlsupportsOOprogramming,Reusable,Packageetc.Perl
codeisplatformindependent.
FirstStep
Createaperlscript(*.pl)withfollowingline.printHello
World\n;Extentionshouldbe.plor.PL.
Savethefileandrunthefollowingcommandfromthefolder
wherethescriptfileexist.perlMyFirst_Perl.pl
SeetheoutputHelloWorldonthescreen.
Ifthefirstnonspacecharofalineis'#'thenthelineis
considerascomment.
Shebang
#!/usr/bin/perl
or
#!/usr/local/perl5/bin/perl
Exceptlastline,allotherlinesshouldendwith';'
ABCDofPerlProgramming
Variables
TherearethreebasictypeofvariablesinPerl.Looselytyped
language.Alltypeofvariablesareprefixedwithasymboleto
denotethetypeofvariable(Scalar$,Array@,Associated
Array%).
Examplescripttodemonstrateonhowtohandlethevariables.
======================================================
#ArrayExample
@names=("Muriel","Gavin","Susanne","Sarah","Ram");
print"Theelementsof\@namesare@names\n";
print"Thefirstelementis$names[0]\n";
print"Thethirdelementis$names[2]\n";
print'Thereare',scalar(@names),"elementsinthearray\n";
#ScalarExample
$num=10;
$num++;
$num;
$num+=3;
print"\$numis$num\n";
Cont...
#AssociatedArraryExample
%countries=('NL','TheNetherlands','BE','Belgium','DE','Germany','MC','Monaco','ES','Spain');
print"Enterthecountrycode:";
chop($find=<STDIN>);
$find=~tr/az/AZ/;
print"$countries{$find}hasthecode$find\n";
foreach(keys%countries){
print"Thekey$_contains$countries{$_}\n";
}
while(($code,$name)=each%countries){
print"Thekey$codecontains$name\n";
}
==============================================================
%my_hash
@my_array
IndexNo
Value
Key
Value
TheNetherlands
NL
TheNetherlands
Belgium
BE
Belgium
Germany
DE
Germany
Monaco
MC
Monaco
Spain
EC
Spain
print"$my_array[1]";
print"$my_hash{'BE'}";
Arrays
*)scalar(@my_array):returnsnumberofelementsinthearray.
*)$#my_array:returnsmaximumnumberofindexi.e.
$#my_array==scalar(@my_array)1
*)Lastelementofanarray:$my_array[$#my_array],
@my_array[1]
*)Individualelements:$names[$x],@names[0..2,4]
*)FunctionsonArrays:push,pop,shift,unshift,splice
Function
Description
Syntax
push
Addsvaluetotheendofthearray
push(@target,add1,add2,
@source[2..4])
pop
Removesandreturnsvaluefromendof
array
$last=pop(@names)
shift
Removesandreturnsvaluefrombeginning $first=shift(@names)
ofarray
unshift
Addsvaluetothebeginningofarray
unshift(@names,$first);
splice
Removeand/orAddelementsfromthe
targetarray.If3rdparameteris0thenitdo
notremoveanyelementfromtarget.
splice(@target,offset,
no_of_element_to_remove,
@add[2..4])
SnippettodemonstrateArraymodification
@names=("Muriel","Gavin","Susanne","Sarah","Ram");
print"Names::@names\n";
print"Numberofelements::",scalar(@names),"MaxIndex::$#names\n";
print"Thefirst,second,thirdandfifthelementsare@names[0..2,4]\n";
print"a)Thelastelementis$names[$#names]\n";
#oneway
print"b)Thelastelementis@names[1]\n"; #differentway
$last=pop(@names);
print"POP::Names:@names\nLast:$last\n";
push(@names,$last);
print"PUSH::Names:@names\nLast:$last\n";
$first=shift(@names);
print"SHIFT::Names:@names\nFirst:$first\n";
unshift(@names,$first);
print"UNSHIFT::Names:@names\nFirst:$first\n";
@cities=("Brussels","Hamburg","London","Breda");
splice(@names,1,2,@cities[1..3]);
print"SPLICE::Names::@names\nCITIES::@cities\n";
AssociatedArray
Action
Example
Assigning
$countries{PT}='Portugal';
or
%countries=('NL','Netherlands','BE','Belgium');
Deleting
delete$countries{NL};
Allthekeys
printkeys%countries;
Allthevalues
printvalues%countries;
ASliceofHash
print@countries{'NL','BE'};
Howmanyelements?
printscalar(keys%countries);
Doesthekeyexist?
print"It'sthere!\n"ifexists$countries{'NL'};
IterationintheFORloop
foreach(keys%countries)
{print"Thekey$_contains$countries{$_}\n";}
or
print"Thekey$_contains$countries{$_}\n"foreachkeys
%countries;
IterationintheWHILEloop
while(($code,$name)=each%countries)
{print"Thekey$codecontains$name\n";}
or
print"Thekey$codecontains$name\n"while($code,
ArithmeticOperators
Operators
Operator
Description
Example
Addition
$c=$a+$b
Subtraction
$c=$a$b
Multiplication
$c=$a*$b
Division
$c=$a/$b
**
Exponents
$c=$a**$b=>7**7=49
Modulus
$c=$a%$b=>7%7=0
AssignmentOperators&Stringconcatenationoperator
Operator
Description
Example
+=
Addition
$a+=$b
Subtraction
$a=$b
*=
Multiplication
$a*=$b
/=
Division
$a/=$b
**=
Exponents
$a**=$b=>$a**=7
%=
Modulus
$a%=$b=>$a%=7
RelationalOperators
Operator
Example
Defined
Result
==,eq
5==5
Test:Is5equalto5?
True
Test:Is7notequalto2?
True
Test:Is7lessthan4?
False
Test:Is7greaterthan4?
True
Test:Is7lessthanorequalto11?
True
Test:Is7greaterthanorequalto11?
False
5eq5
!=,ne
7!=2
7ne2
<,lt
7<4
7lt4
>,gt
7>4
7gt4
<=,le
7le11
LogicalOpertors
>=,ge
7>=11
Operator
&&,and
7<=11
||,or
Defined
7ge11
AssociatestwovariablesusingAND
AssociatestwovariablesusingOR
Example
if(($x&&$y)==5)...
if(($x||$y)==5)...
IFloop
ConditionalLoops
if(Booleanexpression)
{Statement1;}
elsif(Booleanexpression)
{Statement2;}
else
{Statement3;}
Example:
if($x==7||$yeq"perl")
{print"X::$xY::$y\n;}
elsif($x==6&&$yeq"perl")
{print"X::$xY::$y\n;}
else
{print"Nomatch;}
FORloop
for($x=0;$x<=$#names;$x++)
{print"Index::$xValue::$names[$x]\n;}
print"$name\n"foreach$name(@names);
print"Thekey$_contains$countries{$_}\n"foreachkeys%countries;
print"Name::$_"for(@names);
for$i(55..75){printchr($i);}ORfor(55..75){printchr($_);}
WHILEloop
while(<booleanexpression>)
{statement1}
while($count<=7)
{print"Count::$count\n";$count++;}
print"Thekey$codecontains$name\n"while($code,$name)=each%countries;
while(<FILE_HANDLER>)
{chomp($_);print"LineNO:$.Line::$_\n);}
$dir=shift||'.';
opendirDIR,$dirordie"Can'topendirectory$dir:$!\n";
while($file=readdirDIR)
{print"Foundafile:'$file'\n";}
NEXT
Placeitinsidetheloop.itwillstopthecurrentiterationandgoontothenextone.
CONTINUE
Executedaftereachloopiterationandbeforetheconditionalstatementisevaluated.A
goodplacetoincrementcounters.
LAST
Laststopstheloopingimmediately(likebreak).
REDO
Redowillexecutethesameiterationoveragain.
Example:
$count=0;$redo=0;
while($count<=7){
if($count==4)
{print"SkipFour!\n";next;}
print"$count\n";
if($redo==0&&$count==2)
{$redo=1;redo;}
lastif$count==6;
}
continue
{$count++;};
TheTruthAccordingtoPerl
TherearemanyPerlfunctionswhichtestforTruth.Someareif,while,
unless.Soitisimportantyouknowwhattruthis,asdefinedbyPerl.
Therearethreemainrules:
1.Anystringistrueexceptfor""and"0".
2.Anynumberistrueexceptfor0.Thisincludesnegativenumbers.
3.Anyundefinedvariableisfalse.Aundefinedvariableisonewhich
doesn'thaveavalue,iehasnotbeenassignedto
Example:
&isit;#$test1isatthismomentundefined
$test1="hello";&isit;#astring,notequalto""or"0"
$test1=0.0;&isit;#$test1isnowanumber,effectively0
$test1="0.0";&isit;#$test1isastring,butNOTeffectively0!
subisit
{
if($test1){print"$test1istrue\n";}#tests$test1fortruthorno
else{print"$test1isfalse\n";}#elsestatementifitisnottrue
}
$name
='Mark';
$goodguy='Tony';
if($name==$goodguy){
print"Hello,Sir.\n";
}else{
print"Begone,evilpeon!\n";
}
Somethingseemstohavegonewronghere.ObviouslyMarkisdifferenttoTony,sowhydoes
perlconsiderthemequal?
MarkandTonyareequalnumerically.Weshouldbetestingthemasstrings,notasnumbers.
Todothis,simplysubstitute==foreqandeverythingwillworkasexpected.
$foo=291;$bar=30;
if($foo<$bar)
{print"$fooislessthan$bar(numeric)\n";}
if($foolt$bar)
{print"$fooislessthan$bar(string)\n";}
The'lt'operatorcomparesinastringcontext,andofcourse<comparesinanumericcontext.
Alphabetically,thatisinastringcontext,291comesbefore30.Itisactuallydecidedbythe
ASCIIvalue,butalphabeticallyiscloseenough
Comparisonoperatoraccordingtodatatype
Comparison
Numeric
String
Equal
==
eq
NotEqual
!=
ne
Greaterthan
>
gt
Lessthan
<
lt
Greaterthanorequalto
>=
ge
Lessthanorequalto
<=
lt
TheGoldenRuleofComparisons
*ifyouaretestingavalueasastringthereshouldbeonlylettersin
yourcomparisonoperator.
*ifyouaretestingavalueasanumberthereshouldonlybenonalpha
charactersinyourcomparisonoperator
*Youcantestnumbersasstringandviceversa.Perlnevercomplains.
Subroutines
InPerl,subroutinesarefunctionsaresubroutines.
Subroutinescantakeparametersanditcanreturnvalues.Thereisno
declarationofsubroutineorfunctioninPerl.
subName
{
my($v1,$v2..$vn)=@_;
.....
return($var1,$var2);(or)return(\@a1,\@a2);
}
my($var1,$var2)=&Name($v1,$v2,@v3);print"V1::$var1,V2::$var2\n";
ormy($a1,$a2)=&Name($v1,$v2,@v3);print"A1::@$a1,A2::@$a2\n;
or&Name($v1,$v2,@v3);
Parameterspassedtoasubroutinesarestoredinaspecialarrayvariable
'@_',Commandlineparametersarestoredinaspecialarrayvariable
'@ARGV'.
Subroutinescanreturn(oneoremore)scalar,(oneormore)array
references.
Namespace&VariableScope
Namespaceisnothingbutacollectionofvalididentifiersinthecurrent
scopeoftheprogramorcode.
Scopingreferstovisibilityofvariables.Adynamicvariableiscreatedvia
local()andisjustalocalvalueforaglobalvariable,whereasalexical
variablecreatedviamy()ismorelikeCauto.
$myvar=10;$localvar=10;
print"Before=>My::$myvarlocal::$localvar\n";
&sub1();
print"After=>My::$myvarlocal::$localvar\n";
subsub1#myvar=20localvar=20
{my$myvar=20;local$localvar=20;print"sub1:My:$myvarlocal:$localvar\n";&sub2();}sub
sub2#myvar=10localvar=20
{print"sub1:My:$myvarlocal:$localvar\n";}
The''usestrict''pragmawillenforcethatallvariablesareeitherlexical,or
fullclassifiedbypackagename.
#!/usr/bin/perl
usestrict;
my$x=10;#youcannotusesimple$x=10
print"X::$x\n;
Snippettoexplainthesubroutine
$x=10;$y=20;$z=30;$area=0;
&printXY();
&swap();
&printXY();
&printMyXY();
my($area,$vol)=&area($x,$y,$z);
print"Area::$areaVol:$vol\n";
my($w1,$w2)=&wordfunc("HelloWorld"); #Assignthearrayreferencestoscalars
print"@$w1and@$w2\n"; #deference,ieaccess,thearraysreferredto
subswap
{$t=$x;$x=$y;$y=$t;}
subprintXY
{print"XY::X=>$xY=>$y\n";}
subprintMyXY
{my$x=100;my$y=200;print"MyXY::X=>$xY=>$y\n";}
subarea
{my($x,$y,$z)=@_;my$area=$x*$y;my$vol=$x*$y*$z;return($area,$vol);}
subwordfunc
{my$phrase=shift;
my(@words,@word1,@word2); #declarethreevariableslexically
@words=split/\s+/,$phrase; #splitthephraseonwhitespace
@word1=split//,$words[0]; #createarrayoflettersfromthefirstword
@word2=split//,$words[1]; #andthesecond
return(\@word1,\@word2); #returnreferencestothetwoarraysscalars
}
Q(uote)functions&UserInput
Therearefourquotefunctionsinperl.
qwQuotewords
qqDoublequote
qSinglequote
qxSinglequoteandexecutethesystemcommand
my@arr=qw(onetwothree);#equaltomy@arr=('one','two','three')
my$foo=7;
my$q=q(itis'worth'$foo);
my$qq=qq(itis"worth"$foo);
my$who=qx(whoami);
print"ARR::@arrq::$qqq::$qqWHO::$who\n";
UserInputi.e.readstdinfilehandler
%countries=('NL','TheNetherlands','BE','Belgium','DE','Germany','MC','Monaco','ES','Spain');
print"Enterthecountrycode:";
chomp($find=<STDIN>);
$find=~tr/az/AZ/;
print"$countries{$find}hasthecode$find\n";
FalsevaluesVsExistence
Perldoeshaveafunctiontotestifsomethingexists.Existence,inPerlterms,meansdefined.
InPerl,wecandeleteascalarvariableusing'undef'.Todeleteakeyvaluepairfromahashusedelete
$arr{'key'}.
$car="HondCity";
&CheckCar;
$car="";&CheckCar;
undef$car;&CheckCar;
subCheckCar
{
print"Caristrue!$car\n"if$car;
print"Carexists!!$car\n"ifdefined$car;
}
Multidimensionarray
my@arr=([1,2,3,'four'],['one','two','three',4]);
print"arr[0][0]=$arr[0][0]\n";
my@row1=qw(000102);
my@row2=qw(101112);
my@row3=qw(202122);
my@arr=(\@row1,\@row2,\@row3);
for($i=0;$i<3;$i++)
{
for($j=0;$j<3;$j++)
{print"arr[$i][$j]=$arr[$i][$j]\n";}
}
FileOperations
InPerl,wecanperformfollowingfileoperations
read,write,append,writewithautobackup.
Read:
my$file="myfile.txt";
openRF,$fileordie"Cannotopen$file:$!\n";
print"LINE:$.is:$_"while(<RF>);
Write:
my$file="myfile.txt";
openOUT,">$file"ordie"Cannotwrite$file:$!\n";
for$i(1..10)
{printOUT"$i:Thetimeisnow:",scalar(localtime),"\n";}
closeOUT;
Append:
my$file="myfile.txt";
openOUT,">>$file"ordie"Cannotwrite$file:$!\n";
for$i(11..15)
{printOUT"$i:Thetimeisnow:",scalar(localtime),"\n";}
closeOUT;
ARGV:
perlmyscript.plmyfile.txt
printwhile<>;orprint<>;
Writeafilewithanautoback.Followingcodedemonstratethesame.
@ARGV="myfile.txt";
$^I=".bk";#letthemagicbegin
while(<>){
tr/AZ/az/;#anothernewfunctionsneakedin
print;#thisgoestothetempfilehandle,ARGVOUT,
#notSTDOUTasusual,sodon'tmesswithit!
}
*)Thenameofthefiletobeinplacededitedistakenfromthefirstelementof@ARGV.Inthiscase,
thatismyfile.txt.Thefileisrenamedtoitsexistingnameplusthevalueof$^I,iemyfile.txt.bk
*)Thefileisreadasusualbythediamondoperator<>,placingalineatatimeinto$_.
*)Anewfilehandleisopened,calledARGVOUT,andnoprizesforguessingitisopenedonafile
calledmyfile.txt.Theoriginalmyfile.txtisrenamed.
*)TheprintprintsautomaticallytoARGVOUT,notSTDOUTasitwouldusually.
Readafilewitharecordorlinedelimiterotherthendefaultnewline
char.
$SHOP="shop.txt";
$/="\n\n";
openSHOPordie"Can'topen$SHOPforread:$!\n";
@list=<SHOP>;#dumps*all*of$SHOPinto@list
foreach(@list){
print"Itemsare:\n$_\n\n";
}
Printparagraphsusing<<TAG
$var='variableinterpolated';
print<<PRT;
Thisisalonglineoftextwhichmightbetoolongtofitonjustoneline
andIwasright,itwastoolongtofitononeline.Infact,itlookslike
itmightverywelltakeuptoFOUR,yesFOURlinestoprint.
Thisisvar"$var'
PRT
Readdirectories,Directoriesarespecialfiles.Aslikenormalfiles,we
canreaddirectoryentries.Therearetwofamouswaystoreada
directoryentries.
<*>
readdir
$dir=shift||'.';
$type=qq(txt);
chdir$dirordie"Can'tchdirto$dir:$!\n";
while(<*>)
{
print"Foundafile:$_\n"ifT;
}
print"\nNOWONLYTEXT(*.txt)FILE
ONLY\n\n";
while(<*.$type>)
{print"Foundafile:$_\n";}
$dir=shift||'.';
opendirDIR,$dirordie"Can'topen
directory$dir:$!\n";
while($file=readdirDIR){
nextif$file=~/^\./;
print"Foundafile:'$file'\n"ifT"$dir/
$file";
}
closedirDIR;
InvokeSystemCommandorProcess
Perlcanstartexternalcommands.Therearefivemainwaystodothis.
*system
*exec
*CommandInput,alsoknownas`backticks`
*Pipingdatafromaprocess
*Quoteexecute(qx)
EXEC
'exec'stopsthecurrentperlscriptandstartstheexternalcommandorprocess.Ifitcan'tstarttheexternal
process,itshouldreturnwithanerrorcode.TheexecfunctiondoesworkproperlyonthestandardPerl
distribution.Thisdoesn'tworkproperlyunderPerlforWin32.
SYSTEM
'system'switchtheprocesscontextfromperlscripttotheexternalprocess.Soyoucanseetheoutputof
externalprocess.Controlcomesbacktocallingperlscriptoncetheprocesshascompleted.Notsowithexec,
whichwillterminateyourperlscriptifitissuccessful.Successfulsystemcallreturns0.Anunsuccessfulone
returnsavaluewhichyouneedtodivideby256togettherealreturnvalue.
system('whoami');print"\n\nResult:$?\n\n";
Backticks
These``aredifferentagaintosystemandexec.Theyalsostartexternalprocesses,butreturntheoutputofthe
process.
$user=`whoami`;print"Useris$user\n";
OpeningaProcess
Theproblemwithbackticksisthatyouhavetowaitfortheentireprocesstocomplete.Thisisa
bigproblemifyouhavelargereturncodesorslowprocesses.
Wecanopenaprocess,andpipedatainviaafilehandleinexactlythesamewayyouwould
readafile.Thecodebelowisexactlythesameasopeningafilehandleonafile,withtwo
exceptions
1.Weuseanexternalcommand,notafilename.That'stheprocessname,inthiscase,'lsl'.
2.Apipe,ie|isappendedtotheprocessname.
openLIST,"lsltr|"ordie"Cannotexecutelsltr:$!";
while(<LIST>)
{print"$.$_";}
Quoteexecute
Anythingwithinqx()isexecuted,anddulyvariableinterpolated.systemoutputstheresultof
thecommandtothescreenwhereasqxdoesnot.
while(<*.txt>)
{
print"$_WC::",qx(wcl$_),"\n";
}
Whentouseexternalcalls
YoushouldusePerlfunctionswherepossibleratherthancalling
externalprogramsbecausePerl'sfunctionsare
*portable
*faster
*don'tusuallyrequireregexingtofindtheresultyouwant
*don'trelyonoutputinaparticularformat,whichmightbechanged
inthenextversionofyourOSorapplication;
*morelikelytobeunderstoodbyaPerlprogrammerforexample,
$files=`ls`;onaUnixboxmeanslittletosomeonethatdoesn'tknow
thatlsistheUnixcommandforlistingfiles,asdirisinWindows.
Avoidusingbackticks(``)allovertheplacewhensystemwilldo.
Youmightgetaverylargereturnvaluewhichyoudon'tneed.
InbuildFunctions
Perlhasnumberofinbuildfunctions.Followingarefewprimaryfunctions.
Split,Join,Grep,Map,Sort.
Split
'split'isusedtosplitthegivenstringbasedonaregex.1stargumentisaregexspecifyingwhattospliton,2nd
argumentisastring,whichwewanttosplitand3rdargumentisoptionalone,whichspecifynoofreturn
valuesfromsplitfunction.
$_='Piper:PA28:Archer:OOROB:Antwerp';
@details=split/:/,$_;
print"$_\n"foreach(@details);
@details=split/:/,$_,3;
print"$_\n"foreach(@details);
openRF,"mark.csv"ordie"cannotopenthefile$file:$!\n";
$,=',';
while(<RF>)
{printsplit/\|/,$_;}
Join
'join'isusedtojoinanarrayofelementswithadelimiter.1stargumentisadelimiterstring,remaining
argumentsaretobemergedasreturnvalue.
$sep=",";@arr=qw(onetwothree);
$join=join$sep,@arr,"four";
print"JOIN::$join\n";
Grep
'grep'isusedtopickamatchingstringoutofgivenarray.1stargumentisaregextoselectthe
string.2ndparameterisanarrayofstrings,outofwhichwehavetoselectmatchstrings.
@stuff=qw(flyingglidingskiingdancingpartiesracing);
@new=grep/ing/,@stuff; #Creates@new,whichcontainsmatching'ing'elements
$matched=grep/ing/,@stuff;
@sel_rep=grep{s/ing//if/^[gsp]/}@stuff;
printjoin":",@stuff,"\n";
printjoin":",@new,"\n";
print"Matchednoofelements::$matched\n";
print"Selectivereplace::@sel_rep\n";
Map
Mapworksthesamewayasgrep,inthattheybothiterateoveralist,andreturnalist.There
aretwoimportantdifferenceshowever
*)grepreturnsthevalueofeverythingitevaluatestobetrue;
*)mapreturnstheresultsofeverythingitevaluates.Thereturnvaluesaredependonthe
function(1stparameter)usedtoevaluatethelist.
@letters=(a,b,c,d,e);
@ords=mapord,@letters;
printjoin":",@ords,"\n";
@chrs=mapchr,@ords;
printjoin":",@chrs,"\n";
Owngrepandmapfunctions
1stparameterofgrepormapisafunction,whichisusedtoevaluatetheentriesofgivenlist.
Youcandefineyourownfunctiontoevaluatetheelements.Returnvalueofthefunctionis
usedbygrepormaptoreturnfinalresult.
@stuff=qw(flyingglidingskiingdancingpartiesracing);
printjoin":",@stuff,"\n";
@mapped=map{&isit}@stuff;
@grepped=grep{&isit}@stuff;
printjoin":",@mapped,"\n";
printjoin":",@grepped,"\n";
subisit
{
($word)=/(^.*)ing/;
if(length$word==3)
{return"ok";}
else
{return0;}
}
Sorting
'sort'isusedtosortarrayofelements,Wearegoingtoseethreetypeofsortsimplesort,
Numericsort,andsortingmultiplelists.
SimpleSort
%countries=('NL','The
Netherlands','BE','Belgium','DE','Germany','MC','Monaco','ES','Spain');
foreach(sortkeys%countries){
print"Thekey$_contains$countries{$_}\n";
}
foreach(reversesortkeys%countries){
print"Thekey$_contains$countries{$_}\n";
}
*keysreturnsalist
*sortexpectsalistandgetsonefromkeys,andsortsit
*reversealsoexpectsalist,soitgetsoneandreturnsit
*thenthewholelistisforeach'dover.
NumericSort
Simplesortcomparestheelementsasstring.Todonumericsort,youdefineyourown
functionusing$aand$bvariables.Youmustfollowperlstandardtodefineasortfunction.
*Youmustuse$a,$btocomparetwovalues.
*Return1if$aisgreaterthan$b
*Return1if$bisgreaterthan$a
*Return0if$aand$bareequal
%countries=('976','Mongolia','52','Mexico','212','Morocco','64','NewZealand','33','France');
foreach(sortsupersortkeys%countries)
{print"$_$countries{$_}\n";}
foreach(sort{$a<=>$b}keys%countries)
{print"$_$countries{$_}\n";}
subsupersort{
if($a>$b)
{return1;}
elsif($a<$b)
{return1;}
else
{return0;}
}
SortingMultipleLists
Youcansortseverallistsatthesametime.
%countries=('976','Mongolia','52','Mexico','212','Morocco','64','NewZealand','33','France');
@nations=qw(ChinaHungaryJapanCanadaFiji);
@sorted=sortvalues%countries,@nations;
foreach(@nations,values%countries){
print"$_\n";
}
print"#\n";
foreach(@sorted)
{print"$_\n";}
ImportantStringFunctioninPerl
Chop
Removesthelastcharacterfromastringirrespectiveofwhateveritis.
chop($var=<STDIN>);orchop($var);
Chomp
Removeslineendingcharactersfromastringorarrayofstrings.
NOTE:Itremovesonlythelineendingcharacter(\n).
chomp($var=<STDIN>);orchomp($var);
Eval
Evaluatesperlcode,thenexecutesit.Anyerrorsarereturnedinthe@avariable.
$a=10;$b=20;$c="\$a+\$b";
print"$c=",eval$c,"\n";#prints$a+$b=30
Index
ThisfunctionreturnsthepositionofthefirstoccuranceofthespecifiedSEARCHstring.IfPOSITION
isspecified,theoccuranceatorafterthepositionisreturned.Thevalue1isreturnediftheSEARCH
stringisnotfound.
indexSTRING,SEARCH,POSITION
indexSTRING,SEARCH
Length
Returnsthelengthofthestringinbytes.
lengthSTRING
Lc
Convertsallcharactersinthestringtolowercase.
$var=lcSTRING;
Lcfirst
Takesastringandretrunsitwiththefirstcharacterinlowercase.
$var=lcfirstSTRING;
Rindex
ThisfunctionreturnsthepositionofthelastoccuranceofthespecifiedSEARCHstring.If
POSITIONisspecified,theoccuranceatorbeforethepositionisreturned.Thevalue1is
returnediftheSEARCHstringisnotfound.
rindexSTRING,SEARCH,POSITION
rindexSTRING,SEARCH
Substr
Thisfunctionsupportsthreesetsofpassedvaluesasfollows:
substr(STRING,OFFSET)
Returnsallcharactersinthestringafterthedesignatedoffsetfromthestartofthepassedstring
substr(STRING,OFFSET,LEN)
Returnsallcharactersinthestringafterthedesignatedoffsetfromthestartofthepassedstringupto
thenumberofcharactersdesignatedbyLEN
substr(STRING,OFFSET,LEN,REPLACEMENT)
ReplacesthepartofthestringbeginningatOFFSETofthelengthLENwiththeREPLACEMENT
string.
Uc
Convertsallcharactersinthestringtouppercase.
ucString
Ucfirst
Takesastringandretrunsitwiththefirstcharacterinuppercase.
ucfirstString
Example:
$mypath=qq(c:\\dir1\\dir2\\dir3\\file.txt);
$file=substr($mypath,rindex($mypath,"\\")+1);
$path=substr($mypath,0,rindex($mypath,"\\")+1);
$drive=substr($mypath,0,index($mypath,":")+1);
$drive=ucfirst($drive);
$replace=substr($mypath,(length$mypath)3,3,"csv");
print"mypath=$mypathlength=",length$mypath,"\n";
print"Drive=$drivePath=$pathfile=$fileoffset=$offsetmypath=$mypathreplaced=$replace\n";
RegularExpression(PowerofPerl)
Regularexpressionisarulewritteninsytacticalnotion.Regexisshort
name.
SimpleRegularExpression
$string=~/pattern/;
print"CapitalofIndia?";
chomp($_=<STDIN>);
print"Youranswerwas:$_\n";
if($_=~/delhi/){
print"Correctanswer!!\n";
}
else
{print"YoubetterleaveIndiaplease:)\n";}
CasesenstivityofRegex
$string~=/pattern/i;
if($_=~/delhi/i)
{print"Correctanswer!!\n";}
CharacterClasses
Squarebracketsenclosessinglecharactertobematched.Youcanuse
morethenoneclasssetinanexpression.Youcanspecifyrangeof
characterstobematchedusing''i.e.AZ.Ifyouwanttomatcha
specialcharacter,youmustescapeiti.e.[\K].Negationcharacter
classisalsopossible[^sa].
@names=qw(KarlsonCarleonKarlaCarlaKarinCarinaeedanotherword);
print"@names\n";
foreach(@names){
if(/[KC]arl/){
print"SimpleMatch!/[KC]arl/::$_\n";}
if(/[KCZ]arl[sa]/)
{print"MatchMulticlass/[KCZ]arl[sa]/::$_\n";}
if(/[JL]ari/)
{print"Matchcharrange/[JL]ari/::$_\n";}
if(/[KCZ]arl[^sa]/)
{print"MatchNegation/[KCZ]arl[^sa]/::$_\n";}
if(/[\K]ee/)
{print"SpecialcharMatch/[\K]ee/::$_\n";}
}
Matchingatspecificpoints
Youcanmatchapatternatbeginningorendofgivenstring.Tomatch
atendofaline,use'$'attheendofsearchpattern.Tomatchapattern
atbeginningofaline,usecaret'^'atthebeginningofsearchpattern.
@mail_ids=qw([email protected]@[email protected]@gmail.com);
foreach(@mail_ids)
{print"gmailids::$_\n"if/gmail\.com$/;
print"Raja'sIDs::$_\n"if/^raja/i;}
Negatingtheregex
Ifyouwanttonegatetheentireregexchange=~to!~
@names=qw(KarlsonCarleonKarlaCarlaKarinCarinaeedanotherword);
print"@names\n";
foreach(@names){
if($_!~/[KC]arl/)
{print"Negate!~/[KC]arl/::$_\n";}
if(!/[KC]arl/)
{print"Negate~/[KC]arl/::$_\n";}
}
ReturningtheMatch
Toreturnamatchingpartofagivenstringenclosethepatternwithinparens.
$_='Myemailaddressis<[email protected]>.';
/<(raj)\@(netcat.co.in)>/i;
print"Foundit!$1at$2\n";
*,+moreflexibilityofregex
*means0ormoreofthepreviouscharacter
+means1ormoreofthepreviouscharacter
$_='Myemailaddressis<[email protected]>.';
print"Match1worked:$1:"if/(<*)/i;
$_='<Myemailaddressis<[email protected]>.';
print"Match2worked:$1:"if/(<*)/i;
$_='Myemailaddressis<[email protected]<<<<>.';
print"Match3worked:$1:"if/(<*>)/i;
$_='HTML<I>munging</I>timeishere<I>again</I>!.';
/<I>(.*)<\/I>/i;
print"Longmatch::$1\n";
/<I>(.*?)<\/I>/i;
print"Stingymatch::$1\n";
1)Match1istrue.Itdoesn'treturnanything,butitistruebecausethereare0<atstartofthestring.
2)Match2works.Afterthe0<atthestartofthestring,thereis1<sotheregexcanmatchthattoo.
3)Match3works.Afterthefailingonthefirst<,itjumpstothesecond.Afterthat,thereareplentymoreto
matchrightupuntiltherequiredending.
4)JustaddaquestionmarkandPerldoesstingymatching
TheDifferenceBetween+and*
Itisimportanttoknowthedifferencebetween+and*
$_='Thenumberis2200andthedayisMonday';
($star)=/([09]*)/;
($plus)=/([09]+)/;
print"Staris'$star'andPlusis'$plus'\n";
$_='Myemailaddressis<[email protected]>!.';
/<([^>]+)/i;
print"Foundit!$1\n";
1)That$starhasnovalue.Itmanagedtomatch0ormorecharactersfrom0to9attheverystartof
thestring.
2)Thesecondregexwith$plusworkedalittlebetter,becausewearematchingoneormore
charactersfrom0to9.Therefore,unlessone0to9isfoundthematchwillfail.Oncea09is
found,thematchcontinuesaslongasthenextcharacteris09,thenitstops.
Reusingthematch\1
'()'returnsthematchedstring,andItcanbereusedwithinthesameregex
toformapreviouslymatchedunknowstring.Forexample,ifwearenot
sureaboutwhatHTMLtagwehavetomatch,thenyoucanusethe
followingsnippet.
$_='HTML<I>munging</I>timeishere<I>again</I>!.';
/<(.*?)>(.*?)<\/\1>/i;
print"Foundit!$2\n";
Easywaytoescapingspecialcharacters
Ifyouwanttomatchthefollowing;http://www.cpan.org/thenthe
regexwouldbe/http:\/\/www\.cpan\.org\//.Tomakeitmoresimple,
Perlallowsyoutopickyourdelimiter,ifyouprefixitwith'm'.
m#http://www\.cpan\.org/#;Wecangofurthermoretoescapevery
thingbyquotingeverything.m#\Qhttp://www.cpan.org/\E#;The\Q
escapeseverythingupuntil\Eortheregexdelimiter.
SubsitutionandYetMoreRegexPower
Toreplacebitsofstring,forexample,'us'with'them'.s/Us/them/;It
replacesonlythefirstoccurance.Itmakeaglobalreplacementuse/g.
s/Us/them/g;Itfailtodoglobalreplacementbecausebydefaultregex
iscasesensitive,use/ig.s/Us/them/ig;Tomakeitmorefitchangeitas
followss/us([,.])/them\1/igors/\bus(\W)/them\1/ig;[\W]=[^\w].
$_='Us?Thebususuallywaitsforus,unlessthedriverforgetsus.';
print"\$_::$_\n";
s/Us/them/;print"s/Us/them/::$_\n";
s/Us/them/g;print"s/Us/them/g::$_\n";
s/Us/them/ig;print"s/Us/them/ig::$_\n";
$_='Us?Thebususuallywaitsforus,unlessthedriverforgetsus.';
s/us[,.]/them\1/ig;print"s/us[,.]/them\1/ig::$_\n";
'x'asanoperatoratprint.\dwhichmeansanythingthatisadigit,that
is09.\D,whichisanythingexcept09.Tonegateanyconstruct,
simplycapitaliseiti.e\W\Detc
print"Enteranumber:";
chop($input=<STDIN>);
if($input=~/\D/)
{print"Notanumber!!!!\n";}
else
{print'#'x18,"\n",'Youransweris',$inputx3,"\n",'#'x18,"\n";}
Findnumberofmatchesanddirectlyassignthematches.
$_='HTML<I>munging</I>timeishere<I>again</I>!What<EM>fun</EM>!';
print"\$_is$_\n";
$found=0;
$found++while/<i>.*?<\/i>/ig;
@words=/<i>(.*?)<\/i>/ig;
print"Found::$foundmatches,wordsare@words\n";
ParentheseswithORandefficientOR
YoucanuseORinyourregexalongwithparentheses.
/o(rd|ne|ld)/gi
Remembertheuseofparentheses,itstoresthematchsinthevariables
called$1,$2...$n.Ifyoudon'twanttostorethematcheswhenyouuse
ORthenuse
/o(?:rd|ne|ld)/g.
print"Givemeaname:";
chop($_=<STDIN>);
print"Goodname\n"if/Pe(?:tra|ter|nny)/;
print"Thematchis:$1:\n";#Thesecondprintstatementdemonstratesthatnothingis
captured
Matchingspecificamountsof...
Thebraces{}specifyhowmanyoftheprecedingcharactertomatchi.e.z{2}matches
exactlytwo'z's.
/z{3}/
3zonly
/z{3,}/
Atleast3z
/z{1,3}/
/z{4,8}/
1to3z
4to8z
print"Howmanylettersdoyouwanttomatch?";
chomp($num=<STDIN>);
print$_="Thelowestformofwitisindeedsarcasm,Idon'tthink.\n";
print"Matched\\w{$num,}:$1\n"if/(\w{$num,})/;
print"Matched\\w{$num,?}:$1\n"if/(\w{$num,}?)/;
Pre,Post,andMatch
Inaregex,wecangetaPrematch($`),Postmatch($'),andMatch($&)
$_='UglyBadGood';
/bad/i; #look,noparens!
print"Postmatch:$'\n";
print"Prematch:$`\n";
print"Match:$&\n";
RHSExpressions/eand/ee
Youcanhaveanexpressionontherighthandsideofareplacement
statementi.e.s/something/expression/eig.
$data="<FONTSIZE=2><FONTSIZE=4><FONTSIZE=6>";
$data1=$data;
print"$data\n";
$data=~s/(size=)(\d)/\1\2*2/ig;print"$data\n";
$data1=~s/(size=)(\d)/$1.($2*2)/eig;print"$data1\n";
$data='Thefunctionis<5funcA>';
$funcA='*2+4';
print"$data\n";
$data=~s/<(\d)(\w+)>/($1+2).${$2}/; #firsttime
print"$data\n";
$data='Thefunctionis<5funcA>';
$data=~s/<(\d)(\w+)>/($1+2).${$2}/e;
#secondtime
print"$data\n";
$data='Thefunctionis<5funcA>';
$data=~s/<(\d)(\w+)>/($1+2).${$2}/ee; #thirdtime
print"$data\n";
=~/^ENDofREGEX$/ige
Modules
Amoduleisapieceofcodewhichliveinaseparatescriptfileoutside
yourcode.
Forexample,youmightwritearoutinetosendemail.Youcouldthen
usethiscodeinseveralotherscriptwhereyouwanttosendemail.
Modulegivesusthereusabilityofexistingcode.
ThebasicPerlpackageincludesalargenumberofmodules.Thereare
hundredsmoreavailableonCPAN(www.cpan.org).
'useMODULE::SUB'isallwhatyouhavetodotouseanexisting
module.
Usercancreatehisownmodules(*.pm).
'uselibPATH'definesthepathofuserdefinedmodules.
'requirefile_name.pl'iskeywordwhichincludeorimportthefile
contentintoyourcode.Afterthe'require'line,youcanusethe
subroutinesinyourcodewhichareavailableinthefile.
packageMyModule;
usestrict;
useExporter;
usevarsqw($VERSION@ISA@EXPORT@EXPORT_OK%EXPORT_TAGS);
$VERSION=1.00;
@ISA=qw(Exporter);
@EXPORT=();
@EXPORT_OK=qw(func1func2);
%EXPORT_TAGS=(DEFAULT=>[qw(&func1)]
Both=>[qw(&func1&func2)]);
subfunc1{returnreverse@_}
subfunc2{returnmap{uc}@_}
1)Firstwegetanamespacebydeclaringapackagename.Thishelpsensureourmodule'sfunctionsandvariables
remainseparatefromanyscriptthatusesit.
2)Usestrictisaverygoodideaformodulestorestricttheuseofglobalvariables.
3)WeneedtousetheExportermoduletoexportourfunctionsfromtheMyModule::namespaceintothemain::
namespacetomakethemavailabletoscriptsthat'use'MyModule.
4)'usevar'Thispragma,onceusedtodeclareaglobalvariable,supersededby'our'declarations,availableinPerl
v5.6.0orlater.Thiswillpredeclareallthevariableswhosenamesareinthelist,allowingyoutousethemunder
"usestrict",anddisablinganytypowarnings.@ISAdefinestheMyModule'isa'Exporter
5)@EXPORTcontainsalistoffunctionsthatweexportbydefault,inthiscasenothing.Thelessyouexportby
defaultisbettertoavoidsaccidentallyclashingwithfunctionsdefinedinthescriptusingthemodule.Ifascript
wantsafunctionletitask.
6)@EXPORT_OKcontainsalistoffunctionsthatweexportondemandsoweexport&func1
&func2onlyifspecificallyrequestedto.
7)%EXPORT_TAGS.Forconveniencewedefinetwosetsofexporttags.The':DEFAULT'tag
exportsonly&func1;the':Both'tagexportsboth&func1&func2.Thishashstoreslabelspointing
toarrayreferences.Inthiscasethearraysareanonymous.
8)Weneedthe1;attheendbecausewhenamoduleloads,Perlcheckstoseethatthemodulereturns
atruevaluetoensureitloadedOK.Youcouldputanytruevalueattheendbut1isthe
convention.
#!/usr/bin/perlw
usestrict;
my@list=qw(I~Am~A~Perl~Hacker!);
#case1
#useMyModule;
#printfunc1(@list),"\n";
#printfunc2(@list),"\n";
#case2
#useMyModuleqw(&func1);
#printfunc1(@list),"\n";
#printMyModule::func2(@list),"\n";
#case3
#useMyModuleqw(:DEFAULT);
#printfunc1(@list),"\n";
#printfunc2(@list),"\n";
#case4
#useMyModuleqw(:Both);
#printfunc1(@list),"\n";
#printfunc2(@list),"\n";
Case1:Becauseourmoduleexportsnothingbydefaultwegeterrorsas&funct1and&funct2
havenotbeenexportedthusdonotexistinthemain::namespaceofthescript.
Case2:ThisworksOK.Weaskourmoduletoexportthe&func1sowecanuseit.Although
&func2wasnotexportedwereferenceitwithitsfullpackagenamesothisworksOK.
Case3:The':DEFAULT'tag*should*export&func1soyoumightexpecttheerrorhereto
concernamissing&func2.InfactPerlcomplainsabout&func1.Hmm,whatisgoingonhere.
TheDEFAULTtagnameisspecialandisautomaticallysetinourmodules%EXPORT_TAGS
hashlikethisDEFAULT=>\@EXPORT.
Case4:Wespecifiedtheexportofbothourfunctionswiththe':Both'thusthisworks.
Note:uselib'/my/dir'orBEGIN{push@INC,'/my/dir'}orBEGIN{unshift@INC,'/my/dir'}
TodenotethepathofyourperlmoduleifitisnotPWD'.'
DBIArchitecture(DBIModule)
TheDBIarchitectureissplitintotwomaingroupsofsoftware:the
DBIitself,andthedrivers.
usestrict;
useDBI;
my$conn;
my$dbh;
my$username="baan";
my$dbname="EUBAAN2P";
my$pwd="ssaerpdbx2511";
$conn='DBI:Oracle:'.$dbname;
$dbh=DBI>connect($conn,
$username,
$pwd,
{RaiseError=>1,AutoCommit=>0,ora_session_mode=>2}
)ordie"UnabletoconnecttoDatabase:$dbname,usinguser::$username\n
ERROR::$DBI::errstr\n";
if($dbh)
{my$sql=qq(selectsysdatefromdual);
my$date="noDate";
my$sth=$dbh>prepare($sql);
$sth>execute();
$sth>bind_columns(undef,\$date);
while($sth>fetch())
{print"\tdatafromoracle$dbname::dateis::$date\n";}
$sth>finish;
$dbh>disconnect();
print"SuccessfullyConnectedandDisconnectedfromDB::$dbname,usinguser::$username$usr";
Automaticerrorchecking
TheautomaticerrorcheckingcapabilitiesoftheDBIoperatesontwo
levels.ThePrintErrorhandleattributetellsDBItocallthePerlwarn()
functionandtheRaiseErrorhandleattributetellsDBItocallthePerl
die()functionuponerror,typicallycausingthescripttoimmediately
abort.{PrintError=>1,RaiseError=>1}.
BecausethestandardPerlfunctionsofwarn()anddie()areused,you
canchangetheeffectsofPrintErrorandRaiseErrorwiththe$SIG{_
_WARN__}and$SIG{__DIE__}signalhandlers.Similarly,adie()
fromRaiseErrorcanbecaughtviaeval{...}.
ErrorDiagnostics
$dh>err()returnstheerrornumberthatisassociatedwiththecurrent
errorflaggedagainstthehandle$dh.
$dh>errstr()returnsastringcontainingadescriptionoftheerror,as
providedbytheunderlyingdatabase.
$dh>state()returnsastringintheformatofthestandardSQLSTATE
fivecharactererrorstring.
Perl(i)threading
WhatIsAThreadAnyway?
Athreadisaflowofcontrolthroughaprogramwithasingle
executionpoint.Threadsareoneofthepiecesofaprocess.Every
processhasatleastonethread.With5.8,though,youcancreateextra
threads.
ThreadSafeModules
perldataisnotsharedamongthreadsbydefault.Modulesthatarenot
taggedasthreadsafeshouldbetested.Youshouldalwaysassumea
moduleisunsafeunlessthedocumentsaysotherwise.Evensomeof
thestandardmodulesaren'tthreadsafe.
BasicThreadSupport
YourprogramscanusetheConfigmoduletocheckwhetherthreads
areenabled.
$Config{useithreads}ordie"RecompilePerlwiththreadstorunthisprogram."
CreatingThreads
usethreadsimportsallthepiecesyouneedtocreatebasicthreads.
usethreads;
$thr=threads>new(\&sub1);
subsub1{print"Inthethread\n";}
Thenew()methodtakesareferencetoasubroutineandcreatesanewthread,whichstarts
executinginthereferencedsubroutine.Controlthenpassesbothtothesubroutineandthecaller.
Youcanpassparameterstothesubroutineasbelow.
$thr=threads>new(\&sub1,"Param1","Param2",$Param3);
$thr=threads>new(\&sub1,@ParamList);
$thr=threads>new(\&sub1,qw(Param1Param2Param3));
create()isasynonymfornew()
WaitingForAThreadToExit
Threadcanreturnvalues.Towaitforathreadtoexitandextractany
valuesitmightreturn,youcanusethejoin().
usethreads;
$thr=threads>new(\&sub1);
@ReturnData=$thr>join;
print"Threadreturned@ReturnData";
subsub1{return"Fiftysix","foo",2;}
IgnoringAThread
join()doesthreethings:itwaitsforathreadtoexit,cleansupafterit,
andreturnsfromthread.Ifyou'renotinterestedinthethread'sreturn
values&don'treallycarewhenthethreadfinishedthenusedetach().
usethreads;
$thr=threads>new(\&sub1);#Spawnthethread
$thr>detach;#Nowweofficiallydon'tcareanymore
SharedAndUnsharedData
Bydefault,nodataisshared.Whenanewperlthreadiscreated,all
thedataassociatedwiththecurrentthreadiscopiedtothenewthread,
andissubsequentlyprivatetothatnewthread.Tosharedataamong
threadsusing:sharedattribute.
usethreads;
usethreads::shared;
my$foo:shared=1;
my$bar=1;
threads>new(sub{$foo++;$bar++})>join;
print"$foo\n";#prints2since$fooisshared
print"$bar\n";#prints1since$barisnotshare
Sharednonscalarvariables
Inthecaseofasharedarray,allthearray'selementsareshared,andfora
sharedhash,allthekeysandvaluesareshared.Thisplacesrestrictionson
whatmaybeassignedtosharedarrayandhashelements:onlysimple
valuesorreferencestosharedvariablesareallowedthisissothata
privatevariablecan'taccidentallybecomeshared.Abadassignmentwill
causethethreadtodie.
usethreads;
usethreads::shared;
my$var=1;
my$svar:shared=2;
my%hash:shared;
...createsomethreads...
$hash{a}=1;#allthreadsseeexists($hash{a})and$hash{a}==1
$hash{a}=$var#okaycopybyvalue:sameeffectasprevious
$hash{a}=$svar#okaycopybyvalue:sameeffectasprevious
$hash{a}=\$svar#okayareferencetoasharedvariable
$hash{a}=\$var#Thiswilldie
delete$hash{a}#okayallthreadswillsee!exists($hash{a})
Notethatasharedvariableguaranteesthatiftwoormorethreadstrytomodifyitatthesametime,
theinternalstateofthevariablewillnotbecomecorrupted.However,therearenoguarantees
beyondthis,asexplainedinthenextsection
ThreadPitfalls:Races
Raceconditionsarecausedbyunsynchronizedaccesstoshareddata.
Withoutexplicitsynchronization,there'snowaytobesurethat
nothinghashappenedtotheshareddatabetweenthetimeyouaccessit
andthetimeyouupdateit.
usethreads;
usethreads::shared;
my$a:shared=1;
$thr1=threads>new(\&sub1);
$thr2=threads>new(\&sub2);
$thr1>join;
$thr2>join;
print"$a\n";
subsub1{my$foo=$a;$a=$foo+1;}
subsub2{my$bar=$a;$a=$bar+1;}
Whatdoyouthink$awillbe?Theanswer,unfortunately,is``itdepends.''Bothsub1()and
sub2()accesstheglobalvariable$a,oncetoreadandoncetowrite.Dependingonfactors
rangingfromyourthreadimplementation'sschedulingalgorithm
Synchronizationandcontrol
Perlprovidesanumberofmechanismstocoordinatetheinteractionsbetweenthemselvesandtheir
data,toavoidraceconditionsandthelike.
Controllingaccess:lock()
Thelock()functiontakesasharedvariableandputsalockonit.Nootherthreadmaylockthe
variableuntilthevariableisunlockedbythethreadholdingthelock.Unlockinghappens
automaticallywhenthelockingthreadexitstheoutermostblockthatcontainslock()function.
usethreads;
usethreads::shared;
my$total:shared=0;
subcalc{
my$par=shift;
{
lock($total);
$total+=$par;
print"tInCALCotal=$total\n";
}
}
my$thr1=threads>new(\&calc,1);
my$thr2=threads>new(\&calc,10);
my$thr3=threads>new(\&calc,11);
$thr1>join;
$thr2>join;
$thr3>join;
print"total=$total\n";
1)lock()blocksthethreaduntilthevariablebeinglockedisavailable.Whenlock()returns,yourthread
canbesurethatnootherthreadcanlockthatvariableuntiltheoutermostblockcontainingthelockexits.
2)It'simportanttonotethatlocksdon'tpreventaccesstothevariableinquestion,onlylockattempts.the
advisoryfilelockingthatflock()givesyou.
3)Youmaylockarraysandhashesaswellasscalars.Lockinganarray,though,willnotblocksubsequent
locksonarrayelements,justlockattemptsonthearrayitself.
4)Locksarerecursive,whichmeansit'sokayforathreadtolockavariablemorethanonce.Thelockwill
lastuntiltheoutermostlock()onthevariablegoesoutofscope.
subdoit{
{
{
lock($x);#waitforlock
lock($x);#NOOPwealreadyhavethelock
{
lock($x);#NOOP
{
lock($x);#NOOP
lockit_some_more();
}
}
}#***implicitunlockhere***
}
}
AThreadpitfall:DeadLocks
Locksareahandytooltosynchronizeaccesstodata,andusingthem
properlyisthekeytosafeshareddata.Unfortunately,locksaren't
withouttheirdangers,especiallywhenmultiplelocksareinvolved.
Considerthefollowingcode:
usethreads;
my$a:shared=4;
my$b:shared="foo";
my$thr1=threads>new(sub{
lock($a);
sleep20;
lock($b);
});
my$thr2=threads>new(sub{
lock($b);
sleep20;
lock($a);
});
1)Thisprogramwillprobablyhanguntilyoukillit.Theonlywayitwon'thangisifoneofthe
twothreadsacquiresbothlocksfirst.Aguaranteedtohangversionismorecomplicated,but
theprincipleisthesame.
2)Thisconditioniscalledadeadlock,anditoccurswhenevertwoormorethreadsaretrying
togetlocksonresourcesthattheothersown.
Semaphores:SynchronizingDataAccess
Semaphoresareakindofgenericlockingmechanism.Intheirmostbasicform,theybehave
verymuchlikelockablescalars,exceptthattheycan'tholddata,andthattheymustbeexplicitly
unlocked.Intheiradvancedform,theyactlikeakindofcounter,andcanallowmultiplethreads
tohavethe'lock'atanyonetime.
usethreads;
useThread::Semaphore;
my$semaphore=newThread::Semaphore;
my$GlobalVariable:shared=0;
$thr1=newthreads\&sample_sub,1;
$thr2=newthreads\&sample_sub,2;
$thr3=newthreads\&sample_sub,3;
subsample_sub{
my$SubNumber=shift@_;
my$TryCount=10;
my$LocalCopy;
sleep1;
while($TryCount){
$semaphore>down;
$LocalCopy=$GlobalVariable;
print"$TryCounttriesleft4sub$SubNumber(\$GlobalVariableis$GlobalVariable)\n";
sleep2;$LocalCopy++;$GlobalVariable=$LocalCopy;$semaphore>up;
}}
$thr1>join;$thr2>join;$thr3>join;
AdvancedSemaphores
Bydefault,semaphoresbehavelikelocks,lettingonlyonethreaddown()themat
atime.However,thereareotherusesforsemaphores.
Eachsemaphorehasacounterattachedtoit.Bydefault,semaphoresarecreated
withthecountersettoone,down()decrementsthecounterbyone,andup()
incrementsbyone.However,wecanoverrideanyorallofthesedefaultssimply
bypassingindifferentvalues.
usethreads;
useThread::Semaphore;
my$semaphore=Thread::Semaphore>new(5);
$thr1=threads>new(\&sub1);
$thr2=threads>new(\&sub1);
subsub1{
$semaphore>down(5);#Decrementsthecounterbyfive
#Dostuffhere
$semaphore>up(5);#Incrementthecounterbyfive
}
$thr1>detach;
$thr2>detach;
Ifdown()attemptstodecrementthecounterbelowzero,itblocksuntilthecounterislargeenough.Note
thatwhileasemaphorecanbecreatedwithastartingcountofzero,anyup()ordown()alwayschangesthe
counterbyatleastone,andso$semaphore>down(0)isthesameas$semaphore>down(1).Manyresources
thatyouwanttomanageaccessforcanbesafelyusedbymorethanonethreadatonce.
Givingupcontrol
Therearetimeswhenyoumayfinditusefultohaveathread
explicitlygiveuptheCPUtoanotherthread.
Perl'sthreadingpackageprovidestheyield()functionthatdoesthis.
yield()isprettystraightforward,andworkslikethis
usethreads;
subloop{
my$thread=shift;
my$foo=50;
while($foo){print"inthread$thread\n"}
$threads>yield;
$foo=50;
while($foo){print"inthread$thread\n"}
}
my$thread1=threads>new(\&loop,'first');
my$thread2=threads>new(\&loop,'second');
my$thread3=threads>new(\&loop,'third')
Someusefulthreadfunctions
threads>self
Thiswillreturnthethreadobjectforthecurrentthread.$threads
>tid
Thiswillreturntheidofthethread.ThreadIDsareintegers,with
themainthreadinaprogrambeing0.CurrentlyPerlassignsauniquetid
toeverythread.
threads>object(tid)
Thiswillreturnthethreadobjectforthethreadassociatedwiththe
specifiedtid.
threads>yield()
ThisisasuggestiontotheOStoletthisthreadyieldCPUtimeto
otherthreads.Youmaydousethreadsqw(yield)thenusejustabareyield
inyourcode.
threads>list()
Thiswillreturnalistofallnonjoined,nondetachedthreads
Pleaseseeproducerandconsumerscripttohaveacompleteexamplefor
threading.
ImportantLinks
MailTutorial:
http://www.sthomas.net/robertsperltutorial.htm#159Anintroduction
Database(DBI):
http://oreilly.com/catalog/perldbi/chapter/ch04.html
Threading:
http://www.mathematik.uniulm.de/help/perl5/doc/perlthrtut.html
SpecialVariable:
http://www.kichwa.com/quik_ref/spec_variables.html
THANKYOU