perl 学习笔记

时间:2023-03-08 15:49:52
perl 学习笔记

一:基础

1:安装perl

     centos: yum -y install perl 
     官网:https://www.perl.org/
     升级到5.22:先下载,执行./install.sh 安装
          报错:/lib64/libc.so.6: version `GLIBC_2.14' not found (required by perl/bin/perl)
          原因:编译时写死了glibc的版本,而系统中只到2.12 ,所以重装glibc即可
          解决:查看glibc版本:rpm -qa |grep glibc
                    下载2.14版本:http://ftp.gnu.org/gnu/glibc/  (官网;http://www.gnu.org/software/libc/)
                    安装:目录下创建:mkdir build && cd build && ../configure --prefix=/opt/glibc-2.14
                            make -j4  && make install 
            增加环境变量:export LD_LIBRARY_PATH=/opt/glibc-2.14/lib:$LD_LIBRARY_PATH  
                     建软链:mv /lib64/libc.so.6 /lib64/libc.so.6.back  && ln -s /opt/glibc-2.14/lib/libc-2.14.so /lib64/libc.so.6
          安装perl,替换软链: mv /usr/bin/perl /usr/bin/perl.5.10 && ln -s /opt/ActivePerl-5.22/bin/perl /usr/bin/perl
          安装过程中提示有文件找不到,创建它即可
2:第一个perl脚本
     创建文件:vim helloword
                    #!/usr/bin/perl

print "Hello , world!\n";

     给权限:  chmod a+x helloword
     运行:     ./helloword
3:数据类型
     1):数字(perl中的数字都以浮点数值使用)
#!/usr/bin/perl
print 1.2;
print 2.000;
print -3;
print -1.2E22;
print 12_321_435;#数字,方便查看
print o377; #八进制
print oxff; #十六进制
print ob11111111;#二进制
print 2+2;
print 2-1.2;
print 1.2 - 3.3;
print 1/3; #内部使用双精度计算
print 1.0/3;
print 1/2.0;
print 10%3;
print 3**3;

2):字符串(使用utf8编码,文件也须要保存为utf8格式)

#!/usr/bin/perl 
use utf8;                             #使用utf8字符集
binmode(STDIN, ':encoding(utf8)');      #使用utf8输入
binmode(STDOUT, ':encoding(utf8)');     #使用utf8输出
binmode(STDERR, ':encoding(utf8)');     #使用utf8输出错误
print 'gbz is good\n';                  #使用单引号的字符常量
print "gbz is good\n";                  #使用双引号的字符常量
print "\x{2744}";                       #双引号的常量自动转义
#perl中的操作符跟据运算符号判断须要的是什么类型的值,并会自动转换
print "he" . " gg\n";                   #.连接符
print "he" * 5 ."\n";                   #*算数运算,把he转为数字为0
print "33he" * 2 . "\n";                #33he转为数字为33
print "he" x 4.8;                       #x字符串复制倍数
print "he" . 3 * 4 ;                    #先算数运算,在字符运算

3):打印错误信息

#!/usr/bin/perl -w      打印简单错误信息
use diagnostics;          #打印详细错误信息
     4):变量(未定义表示undef)
#!/usr/bin/perl
use utf8
$age = undef;
$age2 = undef;
print $age += 1; #与数字运算时,表示0
print "gbz" . $age2 . "gbz";   #与字符运算时,表示空串
print defined(undef);    #判断是否为undef,是:空,否:1
$name = "gbz"; #变量名要有意义
$name_length = length($name); #包括字母下划线等
print $name;
print "${name} is size : $name_length\n";       #字符串中引用尽量使用${}
$ord_name = ord($name);   #一个字符转换为码值
print $ord_name . "is " . chr($ord_name);  #码值转字符
     5)运算符
          #!/usr/bin/perl

use utf8;
#字符比较符:eq,ne,lt,gt,le,ge
#数字比较符:==,!=,< ,> ,<=,>=
print '1' eq '1';   #字符串比较,true 返回1
print '2' eq '1';   #字符串比较,false 不返回
print 1 == 1;       #数字比较
print 2 == 1;

$name = '\n';
if(''|0|'0'|$name){ #假:空,数字0,字符0
print 'true';
}else{
print 'flase';
}

$line = <STDIN>;  #用户输入流,以回车结束
if($line eq "\n"){
print "this is blank!\n";
}else{
print "not blank: $line";
}

chomp($line);    #去掉末尾回车符,返回1,否则返回0
chomp($line2 = <STDIN>); #先去掉回车,再赋值给变量
print $line2;
$line3 = <STDIN>;
print chomp $line3; #perl方法可以不用括号

$count = 0;
while($count < 10){
    $count += 2;
    print "${count}\n";
}

6):列表和数组

           #!/usr/bin/perl
use utf8;
$list[0] = 1;  #数组从0开始
$list[1] = '2'; #可以存放不同类型的值
$list[100] = 100; #创建了101个元素,中间的值为undef
print $list[0] . '--' . $list[100] . '--' . $list[50] . '--';
print $list[1.22];  #下标去掉小数
print $list[-1];    #最后一个

print "\n";
$list = 111;
print $list; #与数组同名的变量,与数组是不相关的两个变量
print $list[-22];

($array11,$array12,$array13) = (1,2,3);  #列表创建及赋值
($array21,$array22) = (1..6); #..范围操作符,把前两个元素赋值
$array3 = qw ( 1 2 3 ); #使用qw 创建数组
$array4 = qw / 1 2 3 4 '1'/;
print $array11; 
print $array22;
print $array4; #返回最后一个元素

@array = (1.2..5.6); #小数会转换成整数
print @array; #@表示整个数组
print pop @array;  #取出末尾一个元素
push @array,1..3;  #把1,2,3放到@array末尾
print @array;
print shift @array; #取出第一个元素 
unshift @array,1;   #把1放到开头
splice @array,1,2,qw(22); #从索引1开始,取出两个元素,用22替换

$_ = '44'; #$_是perl的默认变量,是全局变量
foreach $_ (@array){ #在循环中$_是局部变量,与全局变量占用不同的存储空间
     print $_ . "\n";
}  
print $_;#循环外打印的是全局变量的值

print reverse 1..6; #倒序
print sort 5..10,'ss',' ',"\n"; #unicode码值顺序

7):map(哈希)

          perl中标量,列表,哈希都有各自的命名空间,即使同名也不影响
          map中key可以是数字,字符串,undef;但都会转为字符串
          map中value可以是数字,字符串,undef,列表等
          创建和取值:
               $map{'name'} = 'gbz';

$map{age} = 25;   #key自动转为字符串
               $map{1} = undef;
               $map{undef} = 1;

               取值:print $map{undef} ;
               删除:delete  $map{name};
               key是否存在:print exists $map{names};     #存在:1  ,不存在:undef
          访问整个map
               print %map;
          转换
               list ==>map : %map = ('name',"gbz",'age',25);    #(key , value , key , value)
               map ==>list:  @array = %map;
               胖箭头:%map = ('name' => "gbz",'age' => 25);    #perl自动把=>转换为,
          keys  values
                %map = ('name' => "gbz",'age' => 25);

@k = keys %map;     #得到所有key

                @v = values %map;     #得到所有value
          遍历
               while( ($key , $value) = each %map ){

print " $key ==> $value";

               }
          读取环境变量:print "home is $ENV{HOME}\n";
 
4:标量上下文和列表上下文(重点)
          在perl中跟据上下文不同,得到的结果也不同:
               @ list = qw ('g','b','z');
               @array = sort @list;   #列表上下文,得到的是g b z 
               $size = 42 + @list;     #标量上下文,得到的是45
          区分标量还是列表主要查看表达式须要什么类型的数据
          在列表上下文中使用产生标量的表达式:产生一个元素的列表
               @list = 6*7;    # (42)
          强制指定标量上下文:print scalar @list;  #得到的是元素个数
          列表上下文中的stdin:@lists = <STDIN>; 返回返有行,直到末尾
          标量上下文中的stdin:$list = <STDIN>;返回下一行数据
5:子程序(方法或函数)
#!/usr/bin/perl
use utf8;
#use strict; #use 5.012 严格编译检查,建意开启
sub max {
     $n += 1; #perl默认变量都是全局变量
     print "number is $n\n";
}
&max;  #调用自定义方法
&max; 
sub max { #会覆盖同名方法,此时上面的两个调用的也是被覆盖的方法
     print "~~~~";
}  
max;    #如可没有和perl内置方法重名可以省略&号调用方法
sub number {
     $n = 0;
     $n + 3; #默认子程序返回值为最后一句代码的值
}  
print &number;
sub return_sub {
     1 + 1;
     return 22; #可以返回列表,标量,undef;    return ; 一般表示程序执行有误
     1 + 2;
}  
print return_sub;
sub unmber_max {
     my($m,$n) = @_;  #my()用来定义私有变量,与方法外同名变量互不影响
     if ($_[0] > $_[1]){ #perl使用@_来接收参数,是私有变量
         $m;                    #也会使用$_[index]数组来接收参数
     }else{
         $n;
     }  
}  
print &unmber_max(19,30);
use 5.010; #foreach须要设定版本才可使用
sub addlist {
     state @lists;   #私有变量,其值会被保存下来,留给下一次子程序执行时继续使用
     foreach my $l (@_){
         push @lists,$l;
     }
     say "this list @lists";
}
addlist(1..4);
addlist(2,7);
say @lists; #方法外不能访问state 定义的变量
 
6:输入与输出
     1)读取标准输入(while会一行一行的读;foreach会读入全部,效率低下)
          while (defined($line = <STDIN>)){

print "I saw ${line}\n";
}
//简写                                                                                                                                  
while (<STDIN>){
    print "I saw $_\n";
}

     2)钻石操作符输入(<STDIN>的简写)
while (<>){
    chomp;      #默认去掉$_后的换行符
    print "I saw $_\n";
}
调用:./io io  #读取“文件io”到标准输入流

     3)标准参数(@ARGV,我们可以修改它)

调用: ./io sub 
默认参数存放到@ARGV 中,<STDIN>依次读取@ARGV中的数据

     4)标准输出(<STDON>)

print("out print str");     #输出到标准输出流
print "out print str";     #简写,去掉括号
print (2+4)*4;       #print (2+4)输出成功返回1,再乘4
printf "hello , %s; in %d days!\n" ,"gbz" , 3;
printf "%g %g %g \n" , 5/2 , 31/17 , 22**33; #数字原样输出
printf "截断,只保留整数部分 %d \n" , 22.334;
printf "||%d||%-6d||\n" , 33 , 55;   #正6左补空格,负6右补空格
printf "||%12.3f||\n" , 43.23525;   #保留3位小数
printf "%.2f%%\n" , 22.45; #百分号
use 5.010;
say "gbz" ;  #自动换行功能
my @list = qw (22.34 11.542 11.667);
printf "the items  are:\n" . ("%10.1f\n" x @list), @list;   #相当于%10.1f\n%10.1f\n%10.1f\n 
                                                                                    #("%10.1f\n" x @list) 标量上下文,@list为元素个数

     5)文件句柄
    命名:一般大写

      perl默认的文件句柄:STDIN、STDOUT、STDERR

      打开文件的方式 :
      open CONFIG, 'io'; #读写方式打开文件,使用CONFIG访问 

        open CONFIG, '<io';#只读方式打开文件   
      open LOG, '>test.io';#覆盖写入文件 
           open LOG, '>>test.io';#追加    
    更好的方式:
     open CONFIG, '<' , 'io';#只读方式打开文件
       open LOG, '>' , 'test.io';#覆盖写入文件
     open LOG, '>>' , 'test.io';#追加
    指定编码:(查看perl支持的:perl -MEncode -le "print for Encode->encodings(':all')")
       open CONFIG, '<:encoding(UTF-8)' , 'io';
            或:open LOG, '>:utf8' , 'test.io';   
           一劳永逸(指定所有输入为utf8):binmode STDIN, ':encoding(UTF-8)';
    有问题的文件句柄:
            open 命令打开文件成功:返回真
                                        失败:返回假 
    输出错误:
      终止程序:die "error : $!";   #perl默认使用$!存放错误信息,会放到标准错误流中
                 不终止:warn "error : $!";
                 自动检错:use autodie;
    关闭句柄:(perl会在程序关闭或重新使用前关闭句柄)
            close LOG;     
    使用文件句柄:
open CONFIG, '<io';
while (<CONFIG>){
chomp;
print $_;
}

    改变输出句柄:

      select LOG;     #默认输出现在为LOG
      $| = 1;            #不缓冲直接输出
        select STDOUT; #还原
      重定向句柄失败后,perl还使用之前的
    包柄存到标量变量中:
        open my $log_fh, '>','io.txt' or die "error : $! \n";  #打开文件,有错误会报错
print {$log_fh} "gbz"; #输入到文件中
while (<$log_fh>){ #读取,'>' 换成 ‘<’
chomp;
print $_;
}