#!/usr/bin/perl use strict; use warnings; my $msg = <<'EOF'; __ __ _ _ \ \ / /__| | | _____ _ __ ___ _ __ ___ ___ _ __ \ \ / / _ \ | |/ / _ \| '_ ` _ \| '_ ` _ \ / _ \ '_ \ \ V / __/ | < (_) | | | | | | | | | | | __/ | | | \_/ \___|_|_|\_\___/|_| |_| |_|_| |_| |_|\___|_| |_| _ _ _ ____ _ _ _ | |_(_) | | _ \ ___ _ __| | | | ___ _ _ __ ___| | | __| | | | |_) / _ \ '__| |_____| |/ / | | | '__/ __| | | |_| | | | __/ __/ | | |_____| <| |_| | | \__ \_| \__|_|_| |_| \___|_| |_| |_|\_\\__,_|_| |___(_) EOF print $msg; # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; print <<'EOF'; HVA ER PERL? * Betyr: Practical Extraction and Reporting Language * Alternativt: Pathologically Eclectic Rubbish Lister * Et cross-platform scriptingspråk skrevet av Larry Wall (han er kul) * Virker i UNIX, Windows, på Mac, i VMS, etc etc * Kildekoden til perl er åpen (GPL) * Et tolket språk (kompileres ikke, "kompileres" hver gang det kjøres). HVORFOR PERL? * Veldig kraftig, du kan gjøre mye med lite kode * Kjapt å skrive * Svært mange ferdige biblioteker ( http://search.cpan.org ) * Det er kult HVORFOR IKKE PERL? * Ting kan fort bli litt grisete om man er syk i hodet eller ikke tenker * Veldig mye ulik syntaks (flere måter å gjøre det samme på) * Det blir en del krangling med Python-folk * Python-folkene kommer sikkert på mer... EOF # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; print <<'EOF' HVA VI SKAL HA I DETTE KURSET Det finnes to typer perl: * Oneliner-perl (kjappe triks man bare skal bruke en gang (eller ha på t-skjorta)) * Produksjonskode-perl (relativt pen, leselig kode) Ikke alle ser denne forskjellen. De som ikke ser denne forskjellen er grunnen til at perl har rykte på seg for å være uleselig og grisete, såkalt "write once". Jeg er ikke så glad i dem som ikke ser forskjellen. Spesielt ikke når jeg må fikse på koden deres. I dette kurset skal vi lære om produksjonskode-perl. Oneliner-perl lærer dere tidsnok selv ;-) EOF # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; print <<"EOF" # Enkel syntaks: * Minner veldig om C, PHP og Java. * { og } deler inn blokker, * ( og ) rundt argumenter, etc (MEN: valgfrie). * Alle statements avsluttes med semikolon EOF # Parenteser rundt er valgfrie. Begge disse virker: print "hei\n"; print("hei\n"); # Parenteser brukes for å angi skop. Dette er spesielt nyttig når man har # flere kommandoer nøstet inni hverandre. Lurer du på om det funker uten # parentes? Da beholder du parentesene. Lesbar kode er viktig. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Variabler og slikt # Variabler, arrays og hasher deklareres med ordet "my". Det holder med ett # ord for å deklarere, siden Perl ikke bryr seg så mye om innholdet i # variabler. Om det er et heltall, et desimaltall eller tekst tas litt på # gefühlen. # En vanlig variabel (såkalt "skalar): my $tall = 15; my $tekst = 'hei'; # En array: my @array; @array = (15, 'hei'); # Definer alle verdier $array[2] = 'gunnar'; # Sett tredje element # En hash: my %hash = ('ottar' => 15, 'pelle' => 17); # Definer alle verdier $hash{'bjarne'} = 13; # Sett verdi for bjarne # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Quoting # Ulike hermetegn oppfører seg forskjellig, på samme måte som i PHP # (PHP rappet det av Perl). my $test = 'ottar'; print "hei $test\n"; # printer dette: hei ottar print 'hei $test\n'; # printer dette: hei $test\n # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Hvordan slå sammen tekst (også likt som i PHP, av samme grunn) # Flere tekststrenger slås sammen med punktum (Java bruker pluss). my $fornavn = "Kjell Magne"; my $etternavn = "Bondevik"; my $fulltnavn = $fornavn . ' ' . $etternavn; # Vi kunne selvsagt også brukt dette, som også er mye vanligere å bruke: $fulltnavn = "$fornavn $etternavn"; # Men av og til er "" upraktisk, som f.eks. om du skal printe ut HTML, # eller har verdiene i noe annet enn variabler. my %verdier = ('uid' => 1015, 'bnavn' => 'kjellmangle'); # Dette: print '' . $verdier{'bnavn'} . "\n"; # Er penere enn dette: print "$verdier{'bnavn'}\n"; # Men begge virker, selv om highlightingen min ikke tror det. # At noe virker men blir highlightet feil er ofte et hint. Ta hintet. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Ting på flere linjer: bruk enten punktum eller <<"EOF";. # Punktum (Som regel best): my $test = "ottar"; my $langvariabel = "Denne teksten på flere linjer er dedikert til\n" . "min gode venn og følgesvenn $test\n"; # <<"EOF"; (Bruk bare når det er _store_ greier, og punktum blir veldig # tungvint. Ikke spesielt viktig å kunne, men greit å vite om): $langvariabel = <<"EOF"; Denne teksten på flere linjer er dedikert til min gode venn og følgesvenn $test EOF $langvariabel = <<'EOG'; Denne teksten på flere linjer er dedikert til min gode venn og følgesvenn $test EOG # Det inni hermetegnene er et merke. Alt helt ned til merket blir med i # variabelen. Hva som skjer med teksten inni avhenger av hermetegnene rundt # merket. Husk å bruke samme merke bare en gang! Pass på semikolonet! # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Logikk med tallverdier # Logikk i perl ligner veldig på andre språk som C, PHP og Java. # 0, tom streng og udefinert er false, det meste annet er true (som i PHP). # IKKE utnytt dette for mye. Det blir vanskelig å lese. Test bare rett på # variabelen om du bruker variabelen som en boolean. # Booleans (1 = sant, 0 = usant): my $boolean = 1; if ($boolean) { print "\$boolean er sann!\n"; # Dette skjer. } else { print "\$boolean er usann!\n"; # Dette skjer ikke. } my $tall = 15; if ($tall > 10) { print "\$tall er over 10!\n"; } elsif ($tall < 5) { # elsif står for "else if" print "\$tall under over 5!\n"; } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Logikk med tekstverdier # Dere som kan PHP er vant til å bruke "==" på tekststrenger. Det virker # IKKE i Perl! I Perl er det egne greier for å sammenligne ord. # De viktigste: # eq: er lik # ne: er ikke lik my $tekst = "banan"; if ($tekst eq "banan") { print "\$tekst er lik banan\n"; } if ($tekst ne "eple") { print "\$tekst er ikke lik eple\n"; } if (length($tekst) > 3) { print "\$tekst er mer enn tre tegn lang\n"; } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## While-loop # En while-loop i perl virker akkurat som i andre språk. Yay! my $counter = 0; while ($counter < 10) { print "tallet er $counter\n"; $counter++; # Øker $counter med 1 } ## For-loop # Virker også som i andre språk! Hurra! for (my $tall = 0; $tall < 10; $tall++) { print "tallet er $tall\n"; } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Foreach-loopen # Denne er litt spesiell. Man har noe lignende i PHP, men syntaksen er ulik. # Foreach går gjennom hvert element i en liste. my @array = ('gunnar', 'ottar', 'per ulf'); # Legg merke til at løpevariabelen $verdi angis utenfor parentesen! foreach my $verdi (@array) { print "$verdi\n"; } # Man kan også bruke foreach til å løpe over alle nøklene i en hash: my %hash = ( 'uid' => 3425, 'bnavn' => 'ottar', 'rnavn' => 'Ottar Evje' ); # Kommandoen "keys" gir ut en array med alle nøklene i hashen, så dette er # egentlig akkurat det samme. foreach my $key (keys %hash) { print $key . " = " . $hash{$key} . "\n"; } # Foreach er dritnyttig! # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Å bryte ut av looper i Perl # Når man skal bryte ut av looper er Perl litt rart. Alt heter noe annet enn # det gjør i andre språk! Dette er jo skikkelig teit, men man venner seg # til det ganske fort. Jeg tipper grunnen er at perl ble laget for å parse # tekst, og da virket disse navnene mer logiske. # # En liten tabell: # +------+-------------+---------------------------------------------+ # | Perl | Andre språk | Betydning | # +------+-------------+---------------------------------------------+ # | next | continue | Hopp over det som er nedenfor og kjør neste | # | | | runde i loopen | # +------+-------------+---------------------------------------------+ # | last | break | Avbryt kjøringen av hele loopen | # +------+-------------+---------------------------------------------+ # Eksempel på next: foreach my $tall (1, 2, 3) { if ($tall == 2) { next; } print "tallet er $tall!\n"; } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Eksempel på "last": Rakettutskyting med forviklinger for (my $tall = 10; $tall > 0; $tall--) { print "$tall...\n"; # Oh no! Når vi kommer til 5 eksploderer raketten! if ($tall == 5) { print "Boom!\n"; last; # Her avbryter loopen } } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ### Hva er egentlig det greiene på toppen av alle foilene? ## Shebangen # # #!/usr/bin/perl er en såkalt shebang. Den forteller hva slags språk # scriptet er skrevet i, og hva slags program som skal brukes til å tolke # det. # # Om ikke shebangen var det ville vi måttet vite hva scriptet var skrevet i, # og selv kjørt programmet med filen som argument. # # Uten shebang: # perl program.pl # # Med shebang: # ./program.pl # # For at programmet skal kunne kjøres direkte må det også være kjørbart. # "chmod +x program.pl" fikser den biffen. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## use strict: # # Uten use strict trenger man ikke å deklarere variabler. Variabler blir # bare opprettet når de trengs av seg selv. Kjekt? Nei. # # Alle variabler som er implisitt deklarert blir nemlig globale. # Globale variabler er ikke bra. # # Dessuten blir det plutselig mulig å bruke samme variabel til flere ting # uten å merke det. Det er heller ikke bra. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use warnings; # Eksempel uten strict. Merk at det ikke er noen "use strict" øverst. # Vi tenker oss en webtjeneste der brukeren kan logge inn. Brukeren er # innlogget som "rob-geir". $user = "rob-geir"; print "Du er logget inn som: $user\n"; # maaaange linjer kode med magi og ting. Vi har helt glemt $user. # Hoi, systemet har en funksjon som lister opp alle som er innlogget. # Akkurat nå er det disse tre: @users = ('ottar', 'rob-geir', 'dan-børge' ); # Vi lister opp alle brukerene. Men hold an! Her brukte vi jo $user på nytt! print "Brukere innlogget: "; for ($i = 0; $i < scalar @users; $i++){ $user = $users[$i]; print "$user "; } print "\n"; # Maaange linjer med kode. Nå har vi glemt brukerlisten. # Nederst på siden vil vi vise hvem som er logget inn en gang til. print "Du er logget inn som: $user\n"; # ---------------------------------------------------------------------------------- #!/usr/bin/perl use warnings; # Warnings betyr akkurat det som står: Advarsler. Det gjør at perl advarer # når noe ser rart ut. Du vil ha det. Om koden din gir advarsler er det fordi # du har gjort noe du ikke burde gjøre. # # Jeg fjernet use strict denne gangen, så det skulle bli lettere å gjøre # noe dumt warnings kunne oppdage. # Eksempel på hvorfor warnings er bra: my $foo = "bar"; print "hei, jeg er $bar\n"; # Å nei! Feil variabelnavn! # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Kompliserte datastrukturer i Perl # Perl versjon 4 (som ingen bruker lenger) hadde ingen støtte for å nøste # arrays og lignende. Todimensjonale arrays var ikke mulig. Folk brukte all # verdens grisete triks for å få til noe tilsvarende. Æsj! # # Perl versjon 5 har egentlig heller ikke støtte for flerdimensjonale arrays # eller sånne ting, men det merker vi ikke stort til. Nå har vi nemlig pekere! # # Pekere i perl kan minne om pointere i C eller objektreferanser i Java. # Vi har arrayen @array my @array = ('ottar', 'spiser', 'fisk'); # Vi lager en referanse my $ref = [ @array ]; # Firkantparenteser til array, akkurat som ved henting # av verdier # Vi får tilbake arrayen med @{}: my @sammearray = @{$ref}; # denne sier: $ref er egentlig en array, altså! # Det samme gjelder for hasher, men med { %hash } og %{$ref} # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Vi kan også gjøre ting litt mer direkte, uten å lage @array først: my $arrayref = [ 'geir', 'liker', 'sko' ]; # Og så kan vi hente ut verdier direkte på to måter. De er omtrent like bra, # så det er bare å velge den du liker best. Personlig derefererer jeg gjerne # referansen og bruker arrayen/hashen direkte etterpå, som på forrige foil. print @{$arrayref}[0] . "\n"; # Bruker @{} som før print $arrayref->[0] . "\n"; # Derefererer peker med ->, som i C. # Det samme virker for hasher: my $hashref = { 'name' => 'ottar', 'liker' => 'sko' }; my %hash = %{$hashref}; print %{$hashref}->{'name'} . "\n"; # Perl liker ikke }{, så vi må ha pil. print $hashref->{'name'} . "\n"; print $hash{'name'} . "\n"; # Legg merke til at den første bare er stygg, og de to siste ligner ganske # mye på hverandre. Ukritisk bruk av referanser kan være en potensiell # feilkilde, siden det er lett å blingse. Bare lag en vanlig hash eller # array, så unngår du problemet. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Så, til poenget: Hvordan lage todimensjonale ting? # Todimensjonale arrays i Perl 5 er en array med arrayreferanser i. # Hva merker vi til dette? Ingen ting. Perl fikser det for oss automatisk. my @array; $array[0] = [ 'rob-geir' ]; # Vi legger en array-referanse fremst i arrayen. # Om vi printer ut $array[0] nå, får vi bare en referanse, omtrent som når vi # printer et rart objekt i Java. Den ser slik ut: "ARRAY(0x814cd28)" print $array[0] . "\n"; # Dette er altså egentlig en referanse. Men vent nå litt, da kan vi jo bruke # pil-notasjonen fra forrige foil! print $array[0]->[0] . "\n"; # Men denne pilen er jo kjedelig å skrive. Det fikser Perl! Det virker nemlig # uten også! print $array[0][0] . "\n"; # Og vips, vi merker ingen ting til dette rare referanse-greiene! # Men, det er jo kjekt å vite om dem. Vi kan nemlig bruke dem andre steder # også. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Men av og til må vi likevel vite om dette rare med pekerene. Si vi lager en # todimensjonal array med navn i: my @array = ( [ 'gunnar', 'ottar', 'bengt-åke' ], [ 'kåre', 'ole-rånni', 'per' ], [ 'kåbbai-laila', 'per-kristian foss' ] ); # Og så vil vi gå gjennom alle verdiene: foreach my $ref (@array) { my @navn = @{$ref}; # Foreach gir oss referansen, så vi lager en array foreach my $navn (@navn) { print "$navn\n"; } print "\n"; # Printer et linjeskift etter hver gruppe } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Å lese inn ting med perl # Noe av det man gjør oftest i perl er å lese inn data. Dette gjør man med # "<>". Omtrent sånn: ## Lese fra standard in # En og en linje: while (my $linje = ) { print $linje; } # Alt inn i en stor array (krever mer minne, unngå om du kan): my @array = ; foreach my $linje (@array) { print $linje; } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Å lese fra en fil: # Åpne filen, eller dø om det ikke virket. open(my $FILDESKRIPTOR, "test.txt") or die("Kunne ikke åpne test.txt: $!"); # Les, og print ut med "> " foran: while(my $linje = <$FILDESKRIPTOR>) { print "> $linje"; } # Lukk. close($FILDESKRIPTOR); # Hett tips: open kan også brukes for å åpne ting for skriving. # Kjør kommandoen "perldoc -f open" for å få masse info om alt du # kan gjøre med open. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Fjerne linjeskift fra det du leser # Til forskjell fra f.eks. sed og grep, fjerner ikke perl linjeskift av seg # selv. Om du ikke vil ha dem, må du fjerne dem. # Til dette har vi kommandoen chomp. while (my $linje = ) { chomp($linje); print "$linje\n"; # ok, litt unyttig å bare sette på igjen linjeskiftet. } # chomp kan også kjøres rett på en hel array. Da fikser den alle verdiene. my @array = ; chomp(@array); # NB! Det er veldig vanlig å glemme chomp, og så fortsette i god tro. # Det kan føre til ekle bugs der linjeskift dukker opp på rare steder. # Jeg vet dette fordi jeg gjør det hele tiden selv ;-) # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Printing i Perl # Hittil har vi bare sett på basic bruk av print. Men print kan brukes til # mer. For eksempel en fildeskriptor: # Dette burde gi morosakene ut på standard error. # PS: Det er IKKE komma etter fildeskriptoren når du printer! print STDERR "Aaaah! Venstre motor brenner!\n"; # Om du åpner noe med skrivetilgang med open kan og også bruke print der. # Dette overskriver test.txt: open(my $DESKR, ">test.txt") or die ("feil ved åpning av test.txt: $!"); print $DESKR "Hei, har du det bra?\n"; close($DESKR); # Print på en array printer alle verdiene: my @linjer = ("hei\n", "ost\n", "banan\n"); print @linjer; # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Printf: Fancy-schmancy printing # Der sitter du med et digert desimaltall, og vil printe det ut med to # desimaler. Printf to the rescue! my $tall = 3.1415; printf("pi: %.2f\n", $tall); # Eller du har en masse tallverdier med ulik lengde, og vil høyurejustere: my @tall = (3, 1337, 25, 254); foreach my $tall (@tall) { printf("tall: %4d\n", $tall); # juksa litt: hardkodet inn maksbredde fire } # Eller du vil printe ut et tall i hex, oktal og desimal, null-paddet til # åtte sifre: printf("hex: %08x %08o %08d\n", 255, 255, 255); # Du kan også lagre resultatet i en annen variabel med sprintf: my $leet = sprintf("%03.2f", 13.37890); print $leet, "\n"; # Dette er litt for omfattende til at vi kan herje veldig mye med det. # "perldoc -f sprintf" har mer info. # # Pass på! Det er lurere å bruke print om du ikke trenger ekstra formatering! # Printf er tregere, og det er lettere å gjøre feil. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Splitting av tekststrenger # Ofte har man en lang greie man vil splitte inn i en array. No problem! my $string = "www.pvv.ntnu.no"; my @deler = split(".", $string); # nå inneholder @deler dette: ('www', 'pvv', 'ntnu', 'no'); # Man kan også splitte på flere tegn: my $verdier = "en, to, tre, fire, fem"; my @verdier = split(", ", $verdier); # I stedet for å skrive en string som tegnet man kan splitte på, kan man også # skrive et regulært uttrykk. Vi tar kanskje noe om regulære uttrykk senere, # hvis vi rekker det. # Å splitte på " " (mellomrom) er litt spesielt. Da oppfører perl seg som awk, # og gir deg alle ordene, uansett hvor mye whitespace det er mellom. my $setn = "hei, jeg er ikke så flink med mellomrom"; my @setn = split(" ", $setn); # Om du vil at det skal bli som i cut, med blanke felter mellom spaces som er # inntil hverandre, bruk regulæruttrykket / /: @setn = split(/ /, $setn); # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Join, det motsatte av split # Hvis du har en array, og skal lage en tekststreng av verdiene, er join # tingen for deg. Den setter sammen alle feltene, med en tekststreng mellom. my @koner = ("magda", "gunhild", "gunda"); my $penliste = join(", ", @koner); print "Koner: $penliste\n"; # Ut kommer dette: "Koner: magda, gunhild, gunda" # Gammelt jegertriks for å lage en diger variabel av en array du har lest inn: my @linjer = ; my $digervariabel = join("", @linjer); # Vi joiner på tom streng # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Magiske variabler i Perl # De magiske variablene i Perl er beryktet, og flittig kritisert av # Python-brukere. Og ja, de er litt ekle. Ikke bruk dem mer enn du må, # og husk å kommentere kode der du eventuelt bruker dem. # Disse tre dukker opp relativt ofte, og man forventes vel egentlig å kunne # dem, så de trenger man ikke forklare i koden. Men husk å forklare eventuelle # andre utskeielser! $_ # Default-variabelen. Om ikke noe er angitt, brukes som regel # denne. Kan stort sett unngås, men av og til lurer den seg inn. @_ # Default-arrayen. Dukker stort sett bare opp som argumentene til # subrutiner (mer om dem senere, om vi rekker det) $! # Feilmelding. Denne variabelen inneholder siste feilmelding. # Den ble brukt etter open for et par foiler siden. # Det er hauger av andre magiske variabler også, men disse tre får holde # inntil videre. Er du nysgjerrig på mer, kjør kommandoen "perldoc perlvar". # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Subrutiner (også kjent som funksjoner eller metoder) # Subrutiner er veldig kjekke for å strukturere scripts. De har litt # annerledes syntaks enn det vi er vant til, men ikke så veldig. # Vi lager en subrutine sub hei () { print "hei!\n"; } # ...og vi kjører den. hei(); # ...og en gang til: hei(); # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Men vi vil kanskje gjerne gi subrutinen noen argumenter. For å fortelle # subrutinen at den skal ta inn to variabler, gir vi den to $-tegn i # parentesen: sub hei($$) { my ($navn, $adjektiv) = @_; # Oi, hva er dette? print "Hei $navn, du er $adjektiv!\n"; } # Og så hilser vi på noen hei("ottar", "kul"); hei("pål", "illeluktende"); # Nå dukket det opp litt nytt, spesielt den rare greia som heter @_. # @_ er en magisk array der alle argumentene ligger. Jeg vet at det er to # argumenter (det står jo "$$" i parentesen), så jeg kan bare hente dem ut # direkte med to variabler inni en parentes. # # Denne parentesen er kanskje litt rar, men det er egentlig bare # array-snarveien baklengs. Husk at vi kan si my @array = ('per', 'pål'); # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Vi vil jo ofte returnere noe fra subrutinene våre. Det er lett. Bare bruk # return $variabel: # Vi lager subrutinen fjortis, som setter masse utropstegn bakerst på # tekst: sub fjortis ($) { my ( $tekst ) = @_; return "$tekst!!!11"; } # Hent ut fjortis-tegnsatt variabel my $fjortis = fjortis("hei"); # Print den. print "$fjortis\n"; # Print en dobbeltfjortis variabel print fjortis(fjortis("hallo")) . "\n"; # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Å sende inn og ut arrays fra subrutiner er lett: # En skikkelig unødvendig og teit subrutine som sorterer mot alfabetet: sub descsort (@) { my @array = @_; my @output = reverse sort @array; return @output; } my @array = ('hei', 'hå', 'aha'); foreach my $ord (descsort(@array)) { print "$ord\n"; } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Å leke med en hash er også temmelig likt: sub print_hash (%) { my %hash = @_; # Hold an! Hva er dette? Hash = Array? Hæ? foreach my $key (keys %hash) { print "$key = " . $hash{$key} . "\n"; } } my %hash = ( 'fnavn' => 'herodes', 'enavn' => 'falsk' ); print_hash(%hash); # Dette med "%hash = @_" virker jo litt sært. Men legg merke til at vi bruker # de samme parentesene for å lage arrays og hasher. Faktisk er det bare piler # stedet for kommaer på annenhver for at det skal bli lettere å se hva som er # hva. # # Når du legger masse verdier inn i en hash gir du den altså bare en array # med verdier, og så blir annenhver verdi nøkkel og innhold. # (dette virker på samme måten i PHP). # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Men hva om vi for eksempel vil gi inn to variabler og en array? sub felleseie ($$@) { my $han = shift; # Hva er denne shift? my $hun = shift; my @eiendeler = @_; print "$han og $hun eier sammen dette:\n"; foreach my $ting (@eiendeler) { print "\t$ting\n"; } } my @eiendeler = ('sofa', 'tv', 'stereo'); felleseie("per", "kari", @eiendeler); # shift(@array) tar første verdi i @array, fjerner den fra arrayen og # returnerer den. ('en', 'to', 'tre') blir altså ('to', 'tre') etter shift. # Slik kan vi fjerne de to første variablene, og sitte igjen med resten, som # er til arrayen. # # Grunnen til at det må gjøres slik er at @_ bare inneholder alle verdiene, # den har ikke system på hva som er hva. # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Men hva med to arrays? @_ vet jo ikke når den ene slutter og den andre # begynner! Da må vi til med referanser igjen! sub tell_penisforlengere (\@\@) { my @biler = @{ $_[0] }; my @baater = @{ $_[1] }; print "Det er ".scalar @biler." bilær og ".scalar @baater."båtær\n"; } my @biler = ('mercedes', 'porsche', 'austin martin'); my @baater = ('sjekte', 'campingcruiser', 'yacht', 'pråm'); tell_penisforlengere(\@biler, \@baater); # Hva er disse backslashene? Bare en annen måte å lage referanser på. # I C ville de tilsvart '&var'. Hvilken du bruker er hipp som happ. # Disse gjør det samme: my $biler; $biler = [ @biler ]; $biler = \@biler; # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Hittil har vi hatt funksjonen øverst i scriptet. Men da må vi jo scrolle # forbi masse drit for å se hva selve programmet gjør (man *skal* gi # subrutinene så logiske navn at man skjønner hva de gjør ut fra navnet. # Dette fikser vi med en prototype. De er omtrent som i C: sub hei ($$); # Og så bruker vi den hei('rob-geir', 'tøff'); hei('gunnar', 'sexy'); # Og her kommer den. sub hei ($$) { my ($navn, $adjektiv) = @_; print "Hei $navn, du er $adjektiv!\n"; } # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; # Om du skriver rekursive funksjoner må du uansett prototype. # La oss se på denne greia som teller nedover (på en skikkelig teit måte): sub tellned ($); sub tellned ($) { my $tall = shift; print "$tall...\n"; if ($tall > 0) { tellned($tall-1); } } tellned(10); # ---------------------------------------------------------------------------------- #!/usr/bin/perl use strict; use warnings; ## Noen siste ord om subrutiner # # I en del gammel eller dårlig kode vil du kanskje oppdage at alle # subrutinekall er med '&' foran, og at ingenting er prototypet. # # Dette var slik subrutiner virket før. De sjekket ikke antall argumenter # eller noe som helst, og man sa fra om at de var subrutiner med &. # Det er fremdeles mulig å gjøre det slik av hensyn til bakoverkompatibilitet, # men IKKE GJØR DET! # # Om man gjør dette forsvinner nemlig alle former for feilsjekking rett i # rett i dass, siden &subrutine() slår av sjekking av antall argumenter og # slikt. Dette er et kjempetriks for å skjule bugs. Just don't do it, okay? # ----------------------------------------------------------------------------------