http://jianlee.ylinux.org/Computer/Perl/perl_base.html
1,第一个Perl程序
Perl的发明人:Larry Wall。
Perl”,指语言本身;“perl”,指程序运行的解释器。
#!/usr/local/bin/perl -w
print "Hello,world!/n";
在Unix系统中,如果文本的第一行前两个字符是“#!”,接着的就是执行下面文件的程序。perl在你的系统的哪里,可以用which 或者whereis来查找。一般都在/usr/bin/perl或者/usr/local/bin/perl这两个地方。-w表示开启警告。
1.1 Perl 内嵌的警告 使用 -w 参数可以打开警告:
$ perl -w perl程序 # 命令行执行警告
#!/usr/bin/perl -w # 源代码中使用警告
1.2 Perl特殊的地方
Perl通常允许使用任意数量的空白(如空格,制表符,换行符)来使程序易于阅读。
Perl中没有“main”程序。
Perl中不需要声明变量。
Perl严格区分大小写。
Perl中的括号可以省略。
Perl中所有数字内部的格式都是双精度浮点数。
2,语法
2.1 标量
标量是 Perl 中最简单的数据类型。大多数的标量是数字(如 255 或 3.25e20)或 者字符串(如 “hello”)。
2.1.1 数字
perl中所有数字内部的格式都是双精度浮点数。程序中的整数被当做等价的浮点数来处理。
浮点数
1.25
-12e-24 #- -12x10 的-24 次方(很小的负数)
-1.2E-23 #指数符号可以大写(E)
整数
-40
61298040283768#为方便阅读可作:61_298_040_283_768
非十进制整数
0377 #八进制数字 377,等同于十进制数字 255
0xff #十六进制数字 FF,等同于十进制数字 255
0b11111111 #等同于十进制数字 255
数字操作符
2+3 #2+3,5
5.1-2.4 #5.1-2.4,2.7
3*12 #3*12,36
14/2 #14/2,7
10.2/0.3 #10.2/0.3,34
10/3 #通常是浮点除,3.33333... ...
2.1.2 字符串
Perl能计算长度,不用靠null来判断字符串是否结束。
单引号字符串
'fred' #四个字符:f,r,e,d
'' #空字符(没有字符)
'hello\n'
'\'\\' #单引号(')跟着反斜线(\)字符串
单引号中的 "\n" 不会被当作换行符来处理。
双引号字符串
"barney" #等同于 'barney'
"hello world\n" #hello world,换行
2.1.3 变量
变量由符号($)后接 Perl 标识符构成。Perl大小写是严格区分的:变量$Fred 和变量$fred是不同的。
$fred = 17;
$barney = "hello";
2.1.4 Boolean 值 perl 没有专门的 Boolean 值, 真假值这样判断:
如果值为数字,0 是 false;其余为真
如果值为字符串,则空串(‘)为 false;其余为真
如果值的类型既不是数字又不是字符串,则将其转换为数字或字符串后再利用上述规则
这些规则中有一个特殊的地方。由于字符串'0' 和数字 0 有相同的标量值,Perl 将它们相同看待。也就是说字符串 '0' 是唯一一个非空但值为 0 的串。
2.1.5 undef 值 一种值。变量被赋值之前使用它会有什么情况发生呢?通常不会有什么严重的后果。变量在 第一次赋值前有一个特殊值 undef, 按照 Perl 来说就是:"这里什么也没有,请继续"。如果这里的“什么也没有”是一些“数字”,则表现为 0。如果是“字符串”,则表 现为空串。但 undef 既非数字也非字符串,它是另一种标量类型。
defined 函数 能返回 undef 的操作之一是行输入操作,。通常,它会返回文本中的一行。 但如果没有更多的输入,如到了文件的结尾,则返回 undef。要分辨其是 undef 还是空串,可以使用 defined 函数, ,如果其参数是 undef 值就返回 false,其他 值返回 true。
$madonna = ;
If ($defined ($madonna)){
print "The input was $madonna";
} else {
print "No input available!\n;
}如果想声明自己的 undef 值,可以使用 undef:
$madonna = undef ; #同$madonna 从未被初始化一样。
2.2 操作符
2.2.1 字符串操作符
链接操作符 "."
"hello"."world" # 同于 "helloworld"
"hello".''."world" # 同于 "hello world"
'hello world'."\n" # 同于 "hello world\n"
重复操作符 "x"
"fred" x 3 # "fredfredfred"
5 x 4 # 等于 "5" x 4, "5555"
2.2.2 数字和字符串之间的自动转换 大多数情况下,Perl 将在需要的时候自动在数字和字符串之间转换。且完全依赖于标量值之间的的操作符。 如果操作符(如+)需要数字,Perl 将把操作数当作数字看待。如果操作符需要字符 串(如 . ), Perl 将把操作数当作字符串看待。
"12" * "3" # * 操作符需要数字,所以结果为 36
"12fred34" * " 3" # 结果仍然是 36 , 后面的非数字部分和前面的空格都过滤掉。
"Z" . 5 * 7 # 等于 "Z".35, 或 "Z35"
2.2.3 二元赋值操作符
$fred+=5;
$barney*=3;
$str .= "";
2.2.4 数字和字符串比较操作符
比较关系数字字符串相等== eq不相等!=ne小于gt小于等于<=le大于等于>=ge
2.3 控制结构
2.3.1 if 控制结构
if ($name gt 'fred') {
print "$name’comes after 'fred' in sorted order.\n";
}
2.3.2 while 控制结构
$count = 0;
while ($count < 10) {
$count + = 2;
print "count is now $count\n";
}
2.4 输入输出
2.4.1 print 输出
print "hello world\n"; #输出 hello world,后接换行符
print "The answer is", 6*7, ".\n"; #其实是列表【变量内插】字符串中引用标量变量。变量内插通常也叫做双引号内插,因为它在双引号中(而非单引号)才有效。
$meal = "brontosaurus steak" ;
$barney = "fred ate a $meal";
$barney = 'fred ate a'.$meal; # 同上
$fred =‘hello’;
print“The name is\$fred .\n”; #打印出美圆符号,变量不会被其值替换
print‘The name is $fred’. “\n”; #同上
【使用花括号】
$what =“brontosaurus steak”;
$n = 3;
print“fred ate $n $whats.\n”; #不是steaks,而是$whats的值
print“fred ate $n ${what}s.\n”; #现在是使用变量$what
print“fred ate $n $what”. “s.\n”; #另一种方法
print‘fred ate ’. $n . ‘’. $what . “s.\n”; #一种复杂的方法
2.4.2 用户的输入 chomp 操作
$text = "a line of text\n"; # 也可以由输入
chomp($text); #去掉换行符(\n)。一步执行:
chomp ($text = ); #读入,但不含换行符chomp 是一个函数。作为一个函数,它有一个返回值,为移除的字符的个数。这个数字基本上没什么用:
$food = ;
$betty = chomp $food; #得到值 1
如上,在使用 chomp 时,可以使用或不使用括号()。这又是 Perl 中的一条通用规则:除非移除它们时含义会变,否则括号是可以省略的。
2.5 列表和数组
#!/usr/bin/env perl -w
$fred[0] = "yabba";
$fred[1] = "dabba";
$fred[2] = "doo";
print @fred;
#print @fred."\n";
2.5.1 qw 简写
#对于列表(“fred”, “barney”, “betty”, “wilma”, “dino”)
qw( fred barney betty wilma dino ) #同上,但输入更少
qw ! fred barney betty wilma dino !
qw# fred barney betty wilma dino # #有些像注释
2.5.2 列表赋值
($fred, $barney, $dino) = ("flintstone", "rubble", undef);
($fred, $barney) = qw ; #两个值被忽略了
($rocks[0],$rocks[1],$rocks[2],$rocks[3]) = qw/talc mica feldspar quartz/;当想引用这个数组时, Perl 有一种简单的写法。在数组名前加@(后没有中括号) 来引用整个数组。 你可以把他读作 "all of the "(所有的)”,所以@rocks 可以 读作 "all of the rocks(所有的石头)"。其在赋值运算符左右均有效:
@rocks = qw / bedrock slate lava /;
@tiny = (); #空表
@giant = 1..1e5; #包含 100,000 个元素的表
@stuff = (@giant, undef, @giant); #包含 200,001 个元素的表
@dino = "granite";
@quarry = (@rocks, "crushed rock", @tiny, $dino);
2.5.3 pop 和 push 操作
@array = 5..9;
$fred = pop(@array); #$fred 得到 9,@array 现在为(5,6,7,8)
$barney = pop @array; #$barney gets 8, @array 现在为(5,6,7)
pop @array; #@array 现在为(5,6)(7 被丢弃了)
push(@array,0); #@array 现在为(5,6,0)
push @array,8; #@array 现在为(5,6,0,8)
push @array,1..10; #@array 现在多了 10 个元素
@others =qw/9 0 2 1 0 /;
push @array,@others; #@array 现在又多了 5 个元素(共有 19 个)
2.5.4 shift 和 unshift 操作 push 和 pop 对数组的末尾进行操作(或者说数组右边有最大下标的元素,这依赖 于你是怎样思考的)。相应的, unshift 和 shift 对一个数组的开头进行操作(数 组的左端有最小下标的元素) 。下面是一些例子:
@array = qw# dino fred barney #;
$m = shift (@array); #$m 得到 "dino", @array 现在为 ("fred", "barney")
$n = shift @array; #$n 得到 "fred", @array 现在为 ("barney")
shift @array; #@array 现在为空
$o = shift @array; #$o 得到 undef, @arry 仍为空
unshift(@array,5); #@array 现在为(5)
unshift @array,4; #@array 现在为(4,5)
@others = 1..3;
unshift @array, @others; #array 现在为(1,2,3,4,5)和 pop 类似,如果其数组变量为空,则返回 undef。
2.5.5 字符串中引用数组 和标量类似,数组也可以插入双引号的字符串中。插入的数组元素会自动由空格分 开:
@rocks = qw{ flintstone slate rubble };
print "quartz @rocks limestone\n"; #输出为 5 种 rocks 由空格分开
2.5.6 foreach 控制结构
foreach $rock (qw/ bedrock slate lava /) {
print "One rock is $rock.\n" ; #打印出 3 种 rocks
}这里的$rock不是这些列表元素中的一个拷贝而是这些元素本身
2.5.7 最常用的默认变量 : $_ 如果在 foreach 循环中省略了控制变量,那 Perl 会使用其默认的变量:$_。除了 其不寻常的名字外,这和普通变量类似,如下面代码所示:
foreach(1..10){ #使用默认的变量$_
print "I can count to $_!\n";
}
$_ = "Yabba dabba doo\n";
print; # 打印出默认变量 $_
2.5.8 reverse 操作 reverse(逆转)操作将输入的一串列表(可能是数组)按相反的顺序返回。
@fred = 6 .. 10;
@barney = reverse (@fred); #得到 10,9,8,7,6
@wilma = reverse 6 . .10; #同上,没有使用额外的数组
@fred = reverse @fred; #将逆转过的字符串存回去
2.5.9 sort 操作
@rocks = qw/ bedrock slate rubble granite /;
@sorted = sort(@rocks); #得到 bedrock, granite, rubble, slate
2.6 子程序
子程序(本章中若无特殊说明,子程序均指subroutine,译者注)的定义可以在程序的任意位置。
2.6.1 使用 sub 定义子程序
sub marine {
$n + = 1; #全局变量$n
print "Hello, sailor number $n!\n";
}
2.6.2 调用子程序
&marine; #输出 Hello, sailor number 1!
&marine; #输出 Hello, sailor number 2!由于所有的被调用的子程序都要返回值,因此使用特殊的返回值语法在大多数情况下是一种浪费。因此Larry 将之简化了。
当Perl 遍历此子程序时,将会计算每一步的值。此子程序中最后计算的值将被返回。注意,“The last expression evaluated”的含义是指最后一个被求值的表达式,而非程序的最后一行。
2.6.3 参数
$n = &max(10,15); # 此子程序有 2 个参数此参数列表被传到子程序中;这些参数可以被子程序使用。当然,这些参数存放在某个地方,在 Perl 中,会自动将此参数列表(此参数列表的另一个名字)自动存放在 一个叫做@_的数组中。子程序可以访问次数组变量来确定此参数的个数以及其值。 这也就是说此子程序参数的第一个值存放在$_[0]中,第二个存放在$_[1],依次类 推。但必须强调的是这些变量和 $_ 这个变量没有任何关系,如$dino3(数组 @dino 的一个元素)和$dino 的关系一样。这些参数必须存放在某个数组变量中, Perl 存放在@_这个变量中。
$n = &max(10,15); #此子程序有2 个参数
sub max{
if($_[0] > $_[1]) {
$_[0];
} else {
$_[1];
}
}
2.6.4 my 变量 默认情况下,Perl 中所有变量都是全局的;
foreach (1..10){
my($square) = $_*$_; #本循环中的私有变量
print "$_ squared is $squrare.\n";
}变量$square 是私有的,仅在此块中可见;在本例中,此块为 foreach 循环块。
my ($num) = @_; # 列表 context, 同($sum) = @_;
my $num = @_; # 标量 context, 同$num = @_;任意参数版本:
$maximum = &max(3,5,10,4,6);
//本程序就可以使用任意多个参数
sub max {
my($max_so_far) = shift @_;
foreach (@_){
if($_>$max_so_far){
$max_so_far=$_;
}
}
$max_so_far; //最后一次计算的默认作为返回值
}
2.7 哈希
2.7.1 什么是哈希 和 Python 的字典一样
2.7.2 哈希元素的存取
$hash {$some_key}作为整体的 hash
要引用整个 hash,使用百分号(“%” )作为前缀。
%some_hash = ("foo",35, "bar", 12.4, 2.5, "hello", "wilma", 1.72e30, "betty", "bye\n");
hash 的值(在列表 context 中)是一个 key/value 对的列表 :
@array_array = %some_hash;
哈希赋值
%new_hash = %old_hash;
%inverse_hash = reverse %any_hash;
大箭头符号 (=>)
my %last_name = (
"fred” => "flintstone",
"dino" => undef,
"barney" => "rubble",
"betty" => "rubble",
);
哈希函数
keys 和 values
my %hash = ("a" => 1, "b" => 2, "c" => 3);
my @k = keys %hash;
my @v = values %hash;
each 函数
while (($key, $value) = each %hash) {
print "$key => $value\n";
}
exists 函数
if (exists $books{$dino}) {
print "Hey, there's a libaray card for dino!\n";
}
delete 函数
my $person = "betty";
delete $books{$person}; # 将$person 的借书卡删除掉
2.8 输入输出
从标准输入设备输入是容易的。使用。在标量 context 中它将返回输入的下一行:
chomp($line=) 由于行输入操作在到达文件的结尾时将返回 undef,这对于从循环退出时非常方便的:
while (defined($line = )) {
print "I saw $line";
}
2.8 哈希
3,程序示例
#!/usr/local/bin/perl -w
@lines = `perldoc -u -f atan2`;
foreach (@lines) {
s//w]+)>//U$1/g;
print;
}
#!/usr/bin/perl
@filename_list=("../tracing023/hadoop-hadoop-jobtracker-tracing023.log","../tracing023/hadoop-hadoop-namenode-tracing023.log","../tracing017/hadoop-hadoop-datanode-tracing017.log","../tracing016/hadoop-hadoop-datanode-tracing016.log","../tracing019/hadoop-hadoop-datanode-tracing019.log","../tracing020/hadoop-hadoop-datanode-tracing020.log","../tracing017/hadoop-hadoop-tasktracker-tracing017.log","../tracing016/hadoop-hadoop-tasktracker-tracing016.log","../tracing019/hadoop-hadoop-tasktracker-tracing019.log","../tracing020/hadoop-hadoop-tasktracker-tracing020.log");
$savefile="./mapAndReduce.result";
&rw($filename,$savefile);
sub rw{
my %map;
my %map_id_time;
#list the ids in jobtracer-tracing017
my %map_ids;
open(IN,$filename_list[0]);
foreach(@lines=)
{
if($_=~/^(.*? .*? ).*Adding task \(REDUCE\) '(attempt_.*?)('| |$|,|\/)/)
{
if(!exists $map_ids{$2})
{
$map_ids{$2}=1;
}
}
}
close IN;
#output the list to file
open(OUT,">ids.result");
foreach(keys %map_ids)
{
print OUT $_."\n";
}
close OUT;
#analyze all the files based on map_ids
foreach(@filename_list)
{
my $filename=$_;
my %tmp_map;
open(IN,$filename);
foreach(@lines=)
{
if($_=~/^(.*? .*? ).*(attempt_.*?)('| |$|,|\/)/ && exists $map_ids{$2})
{
if(!exists $tmp_map{$2})
{
$tmp_map{$2}="\n---------[LOG:".$filename."]---------\n";
}
$tmp_map{$2}.=$_;
if(!exists $map_id_time{$2})
{
$map_id_time{$2}=$1;
}
}
}
foreach(keys %tmp_map)
{
$map{$_}.=$tmp_map{$_};
}
close IN;
}
open(OUT,">".$savefile);
my @list_time_id;
my $index=0;
foreach(keys %map_id_time)
{
$list_time_id[$index][0]=$map_id_time{$_};
$list_time_id[$index][1]=$_;
$index++;
}
my @sort_list_time_id=sort {$a->[0] cmp $b->[0]} @list_time_id;
#@blk_list2=sort {$a cmp $b} @blk_list;
for(my $i=0;$i
{
#print $sort_list_time_id[$i][0]."\n";
my $tmp_id=$sort_list_time_id[$i][1];
print OUT "\n/***********".$tmp_id."**********/\n";
print OUT $map{$tmp_id};
print OUT "\n";
}
close OUT;
}