zoukankan      html  css  js  c++  java
  • 《Perl语言入门》学习笔记

    0.前言

    本文主要是记录perl学习中的一些关键知识点,尽可能帮助平日的脚本开发需要
    

    1.标量数据

    a 数字

    perl内部对数字,统一都是按照双精度浮点数double类型来存储的,
    

    b 字符串

    最短的字符串是不含任何字符的空串,最长的字符串没有限制
    
    字符串相关操作
    • 分割:使用的是split函数,split /,/ $str 等价于split(/,/, $str),返回的是数组
    • 连接:字符串的连接使用的是符号.来进行,例如 $newStr=$a . " " . $b;
    • 重复:例如需要得到abcabcabc,那么可以根据字符串进行这样的操作 "abc" x 3
    • 子串:substr()获取子串,substr(字符串,开始的索引位置,长度,替换的字符串)
    • 长度:length()返回
    • 比较:字符串的比较用的是eq ne

    perl中的字符串和数字会自动转换,具体情况是看使用了什么操作符

    数字的飞碟操作符

    a <=> b 表示对数字a和数字b进行比较,返回-1,0,1三种结果

    2.变量

    变量的类型主要是有这么几种

    • 标量:$a = 1
    • 数组: @a = (1, 2, 3)
    • hash: %a = ('a' => 0, 'b' => 1, 'c' => 2)

    perl的三种变量是存在不同的命名空间里,所以 $a, @a, %a 三者是不冲突的。但我们应该避免这样命名,可读性还是很糟糕的。

    字符串标量内插

    被双引号包裹的字符串,可以使用变量内插,这个和linux shell中的一样,例
    "hello $name" 等价于 'hello' . $name

    3.控制结构

    if

    这个与java中的一样,唯一不同的是,逻辑判断可以使用 and, not, or, xor, 还有 ne, eq 等等
    值得注意的是,与js一样,if对不同类型的变量的布尔值处理也是有规律的

    • 0 false, 其他数值都是true
    • 值为字符串,空字符串是假,其他有长度的为真
    • 既不是数字,也不是字符串,就会先试图转换为数字或者字符串
    unless

    unless 等于 if ( not xxxx) 这个样子

    unless (a == 1) {
    	# do something
    }
    
    elsif

    等于java中的else if

    获取行输入

    获取用户的行输入,使用的是句柄<STDIN>,返回一个字符串,并且一般最后带有一个换行符。

    $ilne=<STDIN>;
    if ($line eq "
    ") {
    	print "That was just a blank line!
    ";
    } else {
    	print "That line of input was $line";
    }
    
    chomp

    只能用于字符串变量上,仅把换行符去掉

    while

    与java一样,真假值得判断和if中的一样

    循环体中的几种控制符
    last

    等于break

    next

    等于continue

    带标签的块

    perl中建议使用大写来作为标签名,标签的使用时 标签名+冒号

    LINE: while(<>) {
    	foreach (split) {
    		last LINE if /__END__/;
    	}
    }
    

    三目运算符

    my $size = 
    	($width <10 ) ? "small" :
    	($width <20 ) ? "medium" :
    	($width <30 ) ? "large" :
    		"extra-large";			#default
    
    undef

    如果没有赋值某个变量,那这个变量的的初始值是undef
    - 当被作为数字使用时,为0
    - 当被当做是字符串使用时,是空串

    defined函数

    该函数可以区分undef和空串,例如在读取文件的时候,当eof了,则会返回undef回来,这个时候就可以通过这个来判断了

    $madona=<STDIN>;
    if (defined($madona)) {
    	print "the input is $madona";
    } else {
    	print "the input is empty
    ";
    }
    

    4.列表与数组

    数组下标从0开始,以此类推,最后一个元素的下标是-1。

    列表直接量

    需要引入列表的时候可以写成数组的样子,在圆括号中用逗号隔开的一系列值

    (1,2,3)
    ("a","b",1)
    (1..100)
    
    qw

    如果只是建立简单的单词列表,那么许多乏味的双引号和逗号会惹人讨厌。perl提供了qw的写法来简化
    qw( a b c d e )

    qw=quoted word,译为加上引号的单词,不论如何,perl会将里面当做是字符串来处理,qw的边界符不仅仅是括号,基本上成对出现的字符就行

    qw ! a b c !
    qw / a b c /
    qw # a b c #
    qw < a b c >
    

    以上的几种写法都是合法的

    列表赋值

    ( $a, $b, $c ) = ("111", "222", "333")
    左侧列表中的三个变量,依次会赋予右侧列表的值

    push pop shift unshift

    push和pop对对数组的最后一个元素来进行操作

    @arr=1..3
    @brr=5..7
    push(@arr, "1")
    push @arr,@brr;  # @arr得到@brr数组的所有元素
    pop(@arr)
    

    shift与unshift刚好相反,是对第一个元素来进行操作的

    shift(@arr)			# 弹出第一个元素
    unshift(@arr,"1")	# 将1添加到第一个位置
    

    foreach

    示例,每次循环迭代的时候,里面的控制变量是数组中的元素本身,任何修改都可以反映到本身。

    @rocks=qw / 1 2 3 4 /
    foreach $rock (@rocks) {
    	$rock = "	$rock";  
    	$rock .= "
    ";
    }
    

    如果我们没有指定控制变量,那么会被默认存在$_

    foreach (1..10) {
    	print "current number $_"
    }
    

    reverse sort

    sort可以指定比较规则,比较规则是一个函数

    sub by_ascii {
    	$a cmp $b;
    }
    my @strings = sort by_ascii @any_strings;
    

    5.子程序

    子程序更像是我们在其他语言中见到的函数,关键词是sub 开头的。子程序可以定义在任何位置,而不必要先声明。

    参数,传给perl的子程序的参数,会被放入到参数数组@_ 中,你可以通过$_[0]这种来进行访问。

    子程序可以通过检查@_的长度,来检查是否传入的参数是否正确。

    sub max {
    	if (@_ != 2) {
    		print "WARNNING...."
    	}
    }
    

    注意注意@_$_是完全不同的,一个是数组长度,一个是在for遍历中代表当前元素的变量

    私有变量

    在没有特殊说明情况下,perl中定义的变量都是全局的,这显然不是一件好事,我们可以通过my来指定变量的作用范围。

    6.输入与输出

    钻石输入符号<> , 我们假设有如下的一个脚本my.pl

    #!/usr/bin/perl
    
    while (defined($line = <>)) {	
    	chomp($line);
    	print "It was $line that I saw
    "
    }
    

    考虑到上面这段代码,钻石操作符是从文件或者标准输入流来读取文件的内容,我们创建一个临时文件,文件的内容如下

    #/tmp/demo1
    hahah
    fdsafdsa
    fdasfdsa
    feiwqrf
    

    然后我们执行命令perl /tmp/my.pl /tmp/demo1 得到的输出内容如下

    It was hahah that I saw
    It was fdsafdsa that I saw
    It was fdasfdsa that I saw
    It was feiwqrf that I saw
    

    命令修改为perl /tmp/my.pl - 就变为了从标准输入来获取内容了

    hahaha
    It was hahaha that I saw
    mymy
    It was mymy that I saw
    ^C
    

    注意,如果在使用钻石操作符去读取多个文件时,其实是这几个文件先被合并为一个大文件了,然后从头开始被顺序的读取下去。而当前正在处理的文件,会在变量$ARGV

    #my.pl
    #!/usr/bin/perl
    
    while (defined($line = <>)) {	
    	chomp($line);
    	print "FILE: $ARGV It was $line that I saw
    "
    }
    
    ---------------------------------------------------------
    
    FILE: /tmp/demo1 It was hahah that I saw
    FILE: /tmp/demo1 It was fdsafdsa that I saw
    FILE: /tmp/demo1 It was fdasfdsa that I saw
    FILE: /tmp/demo1 It was feiwqrf that I saw
    FILE: /tmp/demo2 It was 1111 that I saw
    FILE: /tmp/demo2 It was 2222 that I saw
    FILE: /tmp/demo2 It was 3333 that I saw
    

    命令行参数列表@ARGV

    文件句柄

    my $fp;
    open($fp, "</tmp/1.txt");
    while (my $line = <$fp>) {
    	....
    }
    close($fp);
    
    改变默认的文件输出
    select SOME_FILE;
    print "123
    ";
    

    一旦切换了默认的输出文件句柄,程序就会一直往那里进行输出。因此比较好的方式是,对不同的输出,进行指定。

    select LOG;
    $|=1; #这行的意思是清除缓冲区的数据
    select STDOUT;
    print LOG "I'm a log"  # 指定输出的句柄
    

    7.哈希

    哈希就像是java语言中的map结构一样。

    访问哈希

    $hash{ $someKey }

    哈希赋值

    在访问哈希的基础上,右边添加一个值,就是已完成赋值了

    访问整个hash

    想要指代整个hash,就需要使用百分号作为前缀,hash可以被转换为列表,是一些简单的键值对列表

    #!/usr/bin/perl
    
    %demo_hash = ( 
    "a" => 1, 
    "b" => 2, 
    "c" => 3, 
    "d" => 4
    );
    
    
    @demo_array = %demo_hash; # 这里会将hash转换为键值对
    my $l = @demo_array;
    print "@demo_array
    ";
    print "size=$l
    "
    
    ------ output --------
    c 3 a 1 b 2 d 4
    size=8
    

    胖箭头

    上面的方式来书写hash显然不是很方便和直观,于是就有了使用胖箭头的方式来进行

    my %hash = (
    	"a" => "1",
    	"aa" => "2",
    	"aaa" => "3"
    )
    

    哈希函数

    keys 和values
    my @k = keys %hash; # 注意这里是要访问整个hash,不用$
    my @v = values %hash;
    
    each

    如果需要罗列键值对,则可以使用each函数

    while ( ($key, $value) = eash %hash ) {
    	print "$key => $value";
    }
    
    嵌套hash
    $some_hash{a}{b}{c} = 1
    
    exists函数

    检查hash中是否有某个键

    if (exists($hash{"a"})) {
    	# do something
    }
    
    delete函数

    从hash中删除指定key的值,如果没有key,则程序会直接结束,而不会有任何的信息输出

    %ENV

    程序运行的环境变量,会在%ENV可以获取到,print "PATH is $ENV{PATH} "

    8.模块

    使用命令来查询本地是否已经安装了某个模块,例如perldoc CGI

    使用模块

    use File::Basename
    #....
    

    导入模块与自定义函数冲突

    有可能你导入的模块与自己定义的函数有着相同的名字,这个时候就需要指定导入的列表
    例如你有定义一个函数dirname,而File::Basename里面也有这个函数。

    use File::Basename qw / basename /; # 引入basename函数
    # or
    use File::Basename qw/ /; #不引入任何函数
    

    9.文件

    文件测试符

    操作符 意义
    -r 对目前用户或组来说是具有可读的
    -w 对目前用户或组来说是具有可写的
    -x 对目前用户或组来说是可执行的
    -o 由目前用户拥有
    -e 是存在的
    -R -W -X -O 是前面4种的大写,表示对实际用户
    -z 文件存在,并没有内容(对目录来说永远为假)
    -s 文件或目录存在,且有内容
    -f 是普通文件
    -d 是普通目录
    -l 是符号链接
    -C 最后一次inode变更后到今天的天数
    -M 最后一次修改到今天的天数
    -A 最后一次访问到尽头的天数

    虚拟文件句柄

    如果我们需要判断一个文件是否是可读可写的,那么我们可能需要使用如下的代码

    if ( -r $file and -w $file ) {
    	# do something
    }
    

    但实际上这是个非常不划算的操作,因为在-r的时候,我们就其实已经拿到了文件的信息,第二次没有必要再获取一次。这个时候就可以使用perl独有的虚拟句柄来解决

    if (-r $file and -w _ ) {
    	# do something
    }
    

    虚拟文件句柄_指代的是最近一次文件查询,它可可以不写在一个表达式里

    if (-r $file) {};
    if (-w _ ) {};
    

    栈式测试

    除了使用虚拟句柄以外,perl还提供了栈式测试的方式

    if (-r -w -x -o $file) {
    	# do something
    }
    

    值得注意的是,栈式写法应该用于返回的都是boolean的测试符,而不要用于返回数字的。

    stat

    stat($file)返回的是一个数组,不同位置代表了不同的信息

    localtime

    获取当前的时间

    目录句柄

    如果想要从目录里获得文件列表,那么可以使用目录句柄。

    opendir($dir, '/tmp/');
    foreach $f (readdir $dir) {
    	print "one file in /tmp/ is $f
    ";
    }
    closedir($dir);
    

    删除,重命名,软链接

    unlink(file1,file2,file3...);
    rename "oldname", "newname";   #必须属于一个盘,其他盘的话则不行
    symlink "realFile" "linkFile"; # 软链接
    

    10.进程管理

    system函数

    启动进程最简单的方式就是通过system函数,例如system "date";
    注意,如果要使用到shell环境的变量,那么一定是要使用单引号,或者转义字符来表示
    system 'ls $HOME' or system "ls $HOME"

    exec 函数

    与system函数用法基本是一样的,但system函数是在perl空闲的时候去调用子程序,而exec是perl进程自己去执行子程序任务。exec一般会同fork一起使用,在吃不准要使用什么的情况下,system一般总是对的。

    写在exec后面的代码是不会被执行的,除非是编程接管启动中的错误

    exec "date"
    die "date couldn't run: $!
    "
    

    反引号获取输出

    有的时候我们想要获取shell的执行结果,而system和exec都是输出到perl的标准输出,那我们就可以考虑使用反引号来获取

    my $now = `date`;
    print "the time is now $now
    ";
    

    奇淫巧技

    智能匹配

    考虑如下这种场景,我们想在哈希中找出包含Fred的key,并将其key打印出来。对此我们首先会想到的方法是,通过循环来遍历,然后对key判断是否包含,判定结果为true则打印出来。

    my $flag = 0;
    foreach my $key ( keys %names ) {
    	next unless $key =~ /Fred/;
    	$flag = $key;
    	last;
    }
    

    上面写法的好处是,对于任何版本的perl都使用。在5.010版本以上,提供了智能操作符,我们可以将上面的需求写作一行。
    say "i found a key matching 'Fred'" if %names ~~ /Fred/;

    正则匹配提取

    考虑到下面2个代码

    #!/usr/bin/perl
    
    my $line = "name: john, age: 18, birthday: 2003.10, height: 188";
    printf("old message= $line
    ");
    if ( $line =~ /name: (w+), age: (d+), birthday: (.+), height: (d+)/) {
    	printf("1=%s 2=%s 3=%s 4=%s
    ", $1,$2,$3,$4);
    } else {
    	printf("nothing
    ");
    }
    
    if ( $line =~ /name: w+, age: d+, birthday: (.+), height: (d+)/) {
    	printf("1=%s 2=%s 3=%s 4=%s
    ", $1,$2,$3,$4);
    } else {
    	printf("nothing
    ");
    }
    

    第一个if条件中,所有的匹配像都被圆括号包裹了,第二个if条件,前面2个没有被包裹。我们运行一下看看结果。

    old message= name: john, age: 18, birthday: 2003.10, height: 188
    1=john 2=18 3=2003.10 4=188
    1=2003.10 2=188 3= 4=
    

    我们发现第二个的if可以匹配到内容,但是$3 $4 的内容都是空的,只有$1 $2有内容,并且内容是有带括号的birthday和height的。所以,perl 正则匹配会将被()包裹的内容存放到$1 $2 ... 的变量中去,这点在实际编程的时候十分的有用。

  • 相关阅读:
    spring mvc + kafka实战
    springboot 实现文件下载功能
    vue前端文件下载
    父类和子类初始化顺序
    几种单例模式
    全链路压测注意点
    压力测试-ab
    压力测试-locust讲解
    Java httpClient 中get, post ,put(form-data & raw), delete方法使用
    RequestBody 和RequestEntity使用
  • 原文地址:https://www.cnblogs.com/westlin/p/14804060.html
Copyright © 2011-2022 走看看