linux-Perl-语言入门

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 的操作之一是行输入操作,<STDIN>。通常,它会返回文本中的一行。 但如果没有更多的输入,如到了文件的结尾,则返回 undef。要分辨其是 undef 还是空串,可以使用 defined 函数, ,如果其参数是 undef 值就返回 false,其他 值返回 true。
$madonna = <STDIN>;
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
小于 < lt
大于 > 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 用户的输入 <STDIN>

chomp 操作
$text = "a line of text\n";    # 也可以由<STDIN>输入
chomp($text);                 #去掉换行符(\n)。
一步执行:
chomp ($text = <STDIN>); #读入,但不含换行符
chomp 是一个函数。作为一个函数,它有一个返回值,为移除的字符的个数。这个数字基本上没什么用:
$food = <STDIN>;
$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 <flintstone rubble slate granite>; #两个值被忽略了
($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 输入输出

从标准输入设备输入是容易的。使用<STDIN>。在标量 context 中它将返回输入的下一行:

chomp($line=<STDIN>)  
由于行输入操作在到达文件的结尾时将返回 undef,这对于从循环退出时非常方便的:
while (defined($line = <STDIN>)) {
   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=<IN>)
	{
		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=<IN>)
		{
		    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<$index;$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;

}














你可能感兴趣的:(linux-Perl-语言入门)