Perl 1-liners LinuxForum 2000 Ole Tange %%slide Ole Tange * er sikkerhedskonsulent hos Uni-C * har brugt Linux siden 1992 * er aktiv på [MISC], [PERL], [MOEDE] og [ITPOLITIK] %%slide Perl 1-linere er: * ikke for begyndere * brug og smid væk programmer - ofte write-only-programmer * praktisk til systemadministration - specielt i kombination med UNIX * eksempler, jeg selv har brugt %%slide Opret en masse filer - 1 * Problemet: - Opret en masse filer på 1000 bytes #!/usr/bin/perl for ($i=0; $i<=10000; $i++) { open(FIL, ">$i") || die; print FIL "x"x1000; close FIL; } %%slide Opret en masse filer - 2 * Perl lukker selv et genåbnet filehandle - close FIL væk * Vi er ligeglade med fejl - || die; væk * 0..10000 sparer tastetryk - for(...) => for $i (0..10000) * $_ sparer tastetryk - for $i (...) => for(0..10000) perl -e 'for(0..10000){open(A,">$_"); print A "x"x1000;}' %%slide Unikke linier * Problemet: - udskriv første forekomst af en given linie - rækkefølgen _skal_ bibeholdes + sort -u = no go #!/usr/bin/perl while(defined($line=<>)) { if(!($seen{$line} > 0)) { print $line } ++$seen{$line}; } %%slide Unikke linier - 2 * $_ sparer plads - $line => $_ * <> er magisk - while => while(<>) * alle tal er sande (undt. 0) - if(...) => if($seen{$_}) * ++ kan være post-increment og dermed i if-sætningen - if(...) => if($seen{$_}++) - ++$seen{$line} væk #!/usr/bin/perl while(<>) { if($seen{$_}++) { print $_ } } %%slide Unikke linier - 3 * Option -n laver implicit while - while(<>) væk * $_ er magisk i print - print $_ => print perl -ne 'if($seen{$_}++) { print }' * $seen{$_}++ vigtig konstruktion %%slide Udskift i en masse filer - 1 * Problem: - Udskiftning af Microsoft med Linux i en masse filer.txt For hver fil: while(<>) { s/Microsoft/Linux/g; print; } %%slide Udskift i en masse filer - 2 * -p laver while(<>) {... print} * -i laver in-place substitution perl -i -pe 's/Microsoft/Linux/g;' *.txt %%slide Mails med samme subject - 1 * Problemet: - Hvor mange mail er der med samme subject? * Ide: - Tæl med $x{$_}++ while(<>) { if($_ =~ /Subject: (Re: *)*(.*)/) { $subject=$2; $a{$subject}++; } } print map {"$a{$_} $_\n"} keys %a} %%slide Mails med samme subject - 2 * -n sparer while(<>) * $_ underforstået * $subject overflødig * $a{...} => $a{$2}++ * Afslutning klares med END {} perl -ne 'if(/Subject: (Re: *)*(.*)/) {$a{$2}++;} END {print map {"$a{$_} $_\n"} keys %a}' %%slide Mails med samme subject - 3 * Måske mere forståelig med short-circuit - && do {} perl -ne '/Subject: (Re: *)*(.*)/ && do {$a{$2}++;}; END {print map {"$a{$_} $_\n"} keys %a}' < ~tange/mail/sslug %%slide gniretros ksibarA - 1 * Problem: - sortering af strenge bagfra - f.eks. til gruppering af emailadresser på domænenavn * Input: foo@bar.org peter@jensen.dk baz@bar.org * Output: foo@bar.org baz@bar.org peter@jensen.dk %%slide gniretros ksibarA - 2 * Ide: - stav alle linier bagfra - sorter dem - stav alle linier bagfra igen perl -ne '$_=reverse $_; print' * -p giver while(<>) { ... print} - print væk * I reverse er $_ magisk - reverse $_ => reverse cat foo |perl -pe '$_=reverse'|sort|perl -pe '$_=reverse' %%slide Find alle -aliases og omskriv dem - 1 * Problem: - Dit mailsystem har problemer med aliases som '-foo' - Du skal bruge en tilrettet liste med problemaliasesne * Input: -Susse-: -Susse-@webmail7.mmmmmpmmf.dk -Annie-: -Annie-@webmail7.mmmmmpmmf.dk -Lis: -Lis@webmail2.mmmmmpmmf.dk * Output: -Susse-@mmmmmpmmf.dk -Susse-@webmail7.mmmmmpmmf.dk -Annie-@mmmmmpmmf.dk -Annie-@webmail7.mmmmmpmmf.dk -Lis@mmmmmpmmf.dk -Lis@webmail2.mmmmmpmmf.dk %%slide Find alle -aliases og omskriv dem - 2 while(<>) { if(/^(-.*):\s*(.*)/) { print "$1\@mmmmmpmmf.dk $2\n"; } } %%slide Find alle -aliases og omskriv dem - 3 * Ide til forkortelse - Brug s/// og udskriv kun, hvis det går godt perl -ne 's/^(-.*):\s*(.*)/$1\@mmmmmpmmf.dk $2/ and print' %%slide Hvornår var sidste hit - 1 * Problem: - I en access_log ønsker vi at få et felt mere nemlig dato for sidste hit fra samme host * Input: + 193.162.152.41 - - [27/Feb/2000:04:43:43 +0100] "GET www.pi.dk/brugerside.htm" 200 3894 "-" "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)" + 193.162.152.41 - - [27/Feb/2000:04:43:55 +0100] "GET www.pi.dk/priser.htm" 200 9556 "http://www.pi.dk/brugerside.htm" "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)" * Output: + 193.162.152.41 - - [27/Feb/2000:04:43:43 +0100] "GET www.pi.dk/brugerside.htm" 200 3894 "-" "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)" - + 193.162.152.41 - - [27/Feb/2000:04:43:55 +0100] "GET www.pi.dk/priser.htm" 200 9556 "http://www.pi.dk/brugerside.htm" "Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)" [27/Feb/2000:04:43:43 +0100] %%slide Hvornår var sidste hit - 2 * Ide: - Husk sidste hit fra dette IP-nr - Hvis der var et forrige hit: udskriv den. while(<>) { /(\S+)\s+[^[]*(\[[^]]*\])/ or die; # $client=$1; # $time=$2; chomp; print $_, " ", ($last{$1}||"-"),"\n"; $last{$1}=$2; } perl -pe 'chomp;/(\S+)\s+[^[]*(\[[^]]*\])/;$_.=" " .($last{$1}||"-")."\n";$last{$1}=$2' access_log %%slide Find bouncende adresser fra Sendmail - 1 * Problem: - Du har en mailfolder fyldt med bounces fra Sendmail. Lav en liste over problem-adresserne * Ide: - Sendmails bounces indeholder: ----- The following addresses had permanent fatal errors ----- ----- Transcript of session follows ----- - Find alle emailadresser mellem de 2 linier %%slide Find bouncende adresser fra Sendmail - 2 while(<>) { /The following addresses had permanent fatal errors/ && do { $inside=1 }; /Transcript of session follows/ && do { $inside=0 }; $inside && do { /<(.*)>/ && print $1."\n"; }; } %%slide Find bouncende adresser fra Sendmail - 3 * $inside er en flip-flop - /foo/ .. /bar/ er også en flip-flop - /The fol.../ + /Transcri.../ + $inside => /The fol.../ .. /Transc.../ && perl -ne '/The following addresses had permanent fatal errors/ .. /Transcript of session follows/ and do { /<(.*)>/ and print $1."\n" %%slide Find den magiske fil - 1 * Problem: - Der er mange filer. - Alle fylder n*100 bytes - Ingen fylder det samme - Der er et hul på 200 - Find den sidste fil før hullet * Input directory: -rw-rw-r-- 1 tange 600 Mar 3 18:47 fil1 -rw-rw-r-- 1 tange 500 Mar 3 18:47 fil2 -rw-rw-r-- 1 tange 400 Mar 3 18:47 fil3 -rw-rw-r-- 1 tange 200 Mar 3 18:47 fil4 -rw-rw-r-- 1 tange 100 Mar 3 18:47 fil5 * Output: fil4 %%slide Find den magiske fil - 2 * Ide: - find alle størrelser - tæl op sålænge der er en størrelse perl -e 'for(<*>){$a{(-s)}=$_} for($t=100;$a{$t};$t+=100){}print $a{$t-100}' %%slide * Spørgsmål?