前言
- 在看这篇文章之前,推荐先看下《卧槽!perl和C语言实现对比,perl代码量太赞了!》,不知道你看了吗2?
- 推荐一些文章:
- Perl系列文章
- 两个半小时学会Perl
- Perl 教程
- 本文内容是基于《Perl语言入门·第七版》整理所得,而且章节标题和书籍基本对应。
- 本文食用方式,推荐使用搜索关键字和查看目录的方式快速索引到需要的内容;
- 本文内容全部是手敲的,难免有错误,望各位看客多多包涵!
- 本文涉及到的习题,基本都实现了,并且同步在了Gitee,按需下载
第1章 简介
- 《Perl语言入门·第七版》
- https://www.learning-perl.com/可以下载源代码

- https://www.cpan.org/是Perl综合典藏网,包含很多基于Perl的内容,如源代码、安装程序、示例文件
第2章 标量数据
- scalar(标量)
- 标量数据:表示数据的内容,就是值;
- 标量变量:表示存储标量数据的容器;
数字
前置零的写法只用于表示数字直接量,不能用于字符串和数字间的自动转换。
字符串
养成加上use utf8;的习惯。
单引号内的字符直接量
- 单引号字符串中,反斜线表示转义的两种情况:
反斜线后面跟反斜线或单引号;
双引号内的字符直接量
- 与单引号相比,转义字符的内容更加强大。
| 组合 | 意义 |
|---|---|
| \n | 换行 |
| \t | 水平制表符 |
| \r | 回车 |
| \f | 换页符 |
| \b | 退格 |
| \a | 系统响铃 |
| \e | 跳出(ASCII编码的转义字符) |
\\ | 反斜线 |
\“ | 双引号 |
| \l | 将下个字母转为小写 |
| \L | 将它后面的所有字符都转为小写,直到\E为止 |
| \u | 将下个字母转为大写 |
| \U | 将它后面的所有字符都转为大写,直到\E为止 |
| \E | 结束\L、\U和\Q开始的作用范围 |
字符串操作符
操作符可以使用句点符号.进行拼接!
Perl的内置警告信息
- 形式1:
#!/usr/bin/perl
use warnings;
- 形式2:
#!/usr/bin/perl -w
- 形式3:
运行时加上-w选项! use diagnostics;报告核心内容
标量变量(variable)
和其他语言一样,只是perl的变量需要拿钱买来,形如$fred
print输出结果
- 用
say代替print输出结果
perl -E 'say q(hello, world)' [255]
hello, world
字符串中的标量变量内插
变量内插有时候又叫双引号内插!
比较操作符
- 注记:
lt:less thangt:greatereq:equal
| 比较 | 数字 | 字符串 |
|---|---|---|
| 相等 | == | eq |
| 不等 | != | ne |
| 大于 | >= | lt |
| 小于 | < | gt |
| 小于或等于 | <= | le |
| 大于或等于 | >= | ge |
if控制结构
- 和其他语言一样
获取用户输入
$line = <STDIN>
chomp操作符
- 取消末尾的换行符
chomp函数的返回值是移除的字符数
chomp($text = <STDIN>);#读取不带换行符的输入
#等价于
$text = <STDIN>;
chomp($text);
while控制结构
- 与其他语言一样
undef值
ubdef作为数字、字符串使用时会被视作数字零、空字符串
defined函数
defined函数:判断某个字符串是否为空,如果是undef,返回假!
习题

第3章 列表与数组
访问数组中的元素
注意$fred[0]与fred是两个不同的东西
特殊的数组索引
如果数组定义如下:
$name[0] = 'a';
······
$name[88] = 'asd';
最后一个元素的索引可以是$#name和-1
列表直接量
(1, 2, 3) #包含三个数字的列表
(1,"fred", 2) #列表内元素存储格式灵活
(1..100) #从1到100的整数序列
qw简写
qw表示为quoted word用引号引用的词或quoted by whitespace用空白引用的词;
("fred", "barney", "betty", "wilma", "dino")
# 等价的几种写法,少了很多引号,方便使用!
qw( fred barney betty wilma dino )
qw! fred barney betty wilma dino !
qw{ fred barney betty wilma dino }
qw[ fred barney betty wilma dino ]
qw/ fred barney betty wilma dino /
qw< fred barney betty wilma dino >
qw# fred barney betty wilma dino #
······
列表的赋值
pop和push操作符
删除和增加数组末尾元素
shift和unshift操作符
删除和增加数组开头元素
splice操作符
splice 最多接收4个参数,分别为目标数组,操作数组的开始索引,操作的元素个数,替换的元素
字符串中的数组内插
- 注意在使用@符号的时候,在输入邮箱的时候,需要用转义符!
foreach控制结构
- 和c++中的增强for循环类似。在这里,perl会有默认变量来接收!
Perl最喜欢用的默认变量:$_
reverse操作符
- 操作后如果需要更数组内容,就需要用数组去接收,否则不会生效!
sort操作符
- 此处的sort还不能很完美的支持数字的排序,因为仅仅根据ascii顺序排序的!
标量上下文与列表上下文
- 此处想表达的是,相同的符号在不同的语境下有不同的含义!
- 比如,
数字 + 数组得到的是数字,数组名与数字进行比较时,数组名返回的是数组的长度
在标量上下文中使用产生列表的表达式
- 同样是
reverse数组操作,接收的类型不同,得到的内容就不同! - 如果是
数组接收,以数组元素为最小单位翻转 - 如果是
标量接收,以最小字符为最小单位翻转
在列表上下文中使用产生标量的表达式
列表上下文中的
- 如果接收的是数组类型,则可以多行输入;
习题

第4章 子程序
- 前文用到内置的系统函数有
chomp,reverse,print - 和其他语言类似,perl也可以自己定义子程序,子程序名属于独立的命名空间,
调用子程序一般需要加上&
定义子程序
- 子程序的形式,如下所示:
sub marine {
$n += 1; # 全局变量$n
print "Hello, sailor number $n!\n"
}
- 与c语言相比,perl子程序的定义可以出现在任何位置,也不需要出现函数的声明;
- 如上的子程序,操作的是全局变量,也就是说,前文用到的
都是全局变量;
调用子程序
- 调用子程序,又可以叫
呼叫子程序; - 子程序名前面加上
&就可以调用,如调用上面的子程序可以用&marine; - 如果学过c/c++,不知道这里是否可以理解为取内存中的地址,然后执行?
返回值
- 调用子程序都会有返回值
- 每次写返回值表达式显得费时费力
- perl的
返回值简化为,返回子程序执行过程中最后一次运算的结果 - 小心检查最后的返回值是不是你想要的内容!你晓得吧!
参数
- 在调用的传参时候,perl会自动参数劣列表转化为数组变量
@_; - 如下定义的子程序,可以使用
&max(10,15);这样的形式进行传参调用!
sub max {
if(@_[0] > @_[1]){
$_[0];
} else {
$_[1];
}
}
子程序中的私有变量
- 使用
my定义私有变量,如下所示
sub max {
my($m, &n); # 该语句块中的新私有变量
($m, &n) = @_; # 将该参数赋值给变量
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
- 当然定义和初始化可以放在一行语句内,如下:
sub max {
my($m, &n) = @_; # 对子程序的参数命名
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
变长参数列表
- 可以在子程序内部开头判断传入参数的个数,是否符合预期!
sub max {
if (@_ != 2) {print "WARNING!应该传入两个参数!"}
my($m, &n) = @_; # 对子程序的参数命名
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
改进版的&max子程序
- 这里其实就是
选择比较法,需要理解的就是@_和$_; @_:子程序参数列表$_:foreach循环读到的值
#!/usr/bin/perl -w
sub max{
my($max_so_far) = shift @_;
foreach (@_) {
if ($_ > $max_so_far) {
$max_so_far = $_;
}
}
$max_so_far;
}
$maximum = &max(3, 5, 10, 4, 6);
print $maximum;
空列表参数
- 需要注意的是,返回值可能为undef
用my声明的词法变量
- my操作符并不会更改变量赋值时的上下文!
my($num) = @_; # 列表上下文,和($num) = @_;相同
my $num = @_; # 标量上下文,和 $num = @_;相同
- my操作符不加括号时,只能声明靠近的单个词法变量!
- 推荐使用my操作符定义自己的私有变量
use strict 编译指令
- 开启这个编译指令,就要求在自定义变量声明前,必须加上
my use strict;:强制使用严格、良好的编程风格use v5.12:自动加载strict编译指令- 大部分人的建议:比屏幕长的程序都应该加上
use strict;
return操作符
- 满足条件后,终止子程序!
省略与号
- 在调用子程序时,传入参数时,可以完全省略
&:编译器能明显感知到调用的是子程序 - 自定义子程序,如果命名与内置函数重名,调用时一定要加上
&
非标量返回值
- 返回值可以是标量,也可以是列表!
持久化私有变量
- 此处引入关键字
state,在子程序中,可以一直存在,小编认为是c语言形式的static的修饰,仍然在全局区!
子程序签名
- 乍一看,这个特性的加入,使其
表现形式越来越像c语言函数的写法!
习题


第5章 输入与输出
读取标准输入
- 行输入操作符:
<STDIN>与Perl的默认变量$_之间并无直接关联! comp:截掉最后的换行符defined:可以用来判断是否读取到末尾!- 下面有两个程序,执行效果相同,但他们的原理真的相同吗?
- while实现的:
while(<STDIN>) {
print "I saw $_";
}
- foreach实现的:
foreach(<STDIN>) {
print "I saw $_";
}
- 结果就是,不一样:
foreach是先把数据全部读进来;而while是读一行执行一行;如果要处理400MB数据,估计还是选择while好一点!
来自钻石操作符的输入
- 钻石操作符
<>的名字竟然是Larry的女儿命名的! - 钻石操作符是行输入操作符的特例,通常会处理所有的输入,所以在程序中一般只出现一次!
- 下面展示两个相同功能的代码!
- 代码1:
while(<>){
chomp;
print "It was $_ that I saw!\n";
}
- 代码2:
while(defined($line = <>)){
chomp($line);
print "It was $_ that I saw!\n";
}
双钻石操作符
- 如果命令行传入的文件名中包含==管道符
|==等特殊字符,就会引发管道等特殊操作。 - 因此引入
<<>>双钻石操作符,功能没变
调用参数
钻石操作符并不会检查命令行参数,其实也只是把命令行参数存放到@ARGV中- 因此,可以通过修改
@ARGV的内容,强制修改钻石操作符要读取的内容 - 如
@ARGV = qw{larry moe curly}; #强制让钻石操作符只读取这三个文件
while(<>){
chomp;
print "It was $_ that I saw in some stooge-link file!\n"
}
输出到标准输出
- 下面两种打印输出有什么区别?
print @array;print “@array”;- 第二行输出的时候,会在元素之间添加空格;
- 行缓冲,也是是用换行符来进行刷新的!
print加括号和不加括号的区别,注意!
用printf格式化输出
- 这里和c语言的格式高度类似,
printf使用后面的括号是选择性的,如果加上,和C语言就一样了! 参数宽度也可以作为参数另外指定!- 如下的格式:
#!/usr/bin/perl -w
use strict;
use warnings;
print "Hello world\n";
printf("这里直接是以字符串的格式输出的:\n");
printf "%*s\n", 10, "wilma";
printf("%*s\n", 10, "wilma");
printf("注意,此处参数宽度用参数传入:\n");
printf "%*.*f\n", 6, 2, 3.1415926;
printf("%*.*f\n", 6, 3, 3.1415926);
- 运行结果如下:
Hello world
这里直接是以字符串的格式输出的:
wilma
wilma
注意,此处参数宽度用参数传入:
3.14
3.142
数组和printf
- 有没有发现和python的格式化输出也一样!
- 再一次感受到,编程思想比编程语言本身重要很多!
my @items = qw{ wilma dino pebbles };
printf "printf输出添加括号:\n";
printf("The items are:\n".("%10s\n" x @items), @items);
printf "printf输出不加括号:\n";
printf "The items are:\n".("%10s\n" x @items), @items;
- 运行结果:
printf输出添加括号:
The items are:
wilma
dino
pebbles
printf输出不加括号:
The items are:
wilma
dino
pebbles
文件句柄
- 注意联系
I/O操作,6个保留的文件句柄:STDIN、STDOUT、STDERR、DATA、ARGV、ARGVOUT
打开文件句柄
open CONFIG, 'dino'; # 可读可写
open CONFIG, '<dino'; # 只读
open BEDROCK, '>fred';# 可写
open LOG, '>>logfile';# 可追加写
open CONFIG, 'dino'; # 可读可写
open CONFIG, '<', 'dino'; # 只读
open BEDROCK, '>', 'fred';# 可写
open LOG, '>>:encoding(UTF-8)', 'logfile';# 可追加写,还可以指定特定编码
以二进制方式读写文件句柄
- 句柄前加上
binmode,直接以二进制数据流的方式读写。即使在二进制文件中碰巧出现内部编码和换行符相同的字符,也不会将其当做文本文件中的换行符来处理。
异常文件句柄的处理
my $success = open LOG, '>>','logfile'; # 通过返回值可以判断是否成功?
if(!$success){
# open 操作失败
}
关闭文件句柄
- 有打开就要有关闭,
close,就如C中,有malloc就要有free;C++中,有new就要有delete;
用die处理致命错误
die函数的参数是要发出的错误信息文本,一般会输出到标准错误流,同时让程序退出运行!- 注意下面程序,
$!记录的是程序最后返回给操作系统的错误代码! - 小编怀疑,
die也是由linux中系统函数perror封装的,但只是猜测
if(! open LOG, '>>', 'logfile') {
die "Cannot create logfile:$!";
}
用warn发出警告信息
- 与
die相比,warn不会终止程序的运行!
自动检测致命错误
- 在使用的时候,在前面加上
use autodie;这种声明,就会自动判断!
使用文件句柄
- 有点像c中的
sprintf
print LOG "Captain's log, stardate 3.145159\n" #输出到文件句柄 LOG
printf STDERR "%d percent complet.\n", $done/$total * 100;
改换用于输出的默认文件句柄
- print和printf的默认输出句柄是
STDOUT,我们可以使用select BEDROCK;格式来进行切换输出句柄
重新打开标准文件句柄
- 在重新打开了 STDERR之后,任何从Perl产生的错误信息都会送到新的文件里。但如果程序执行到die这部分的代码,那会怎样呢?也就是说,如果无法成功打开文件来接收错误信息,那么错误信息会流到哪里去?
- 在重新打开这三个系统文件句柄 STDIN、 STDOUT或 STDERR失败时,Perl会热心地帮你找回原先的文件句柄。也就是说,Perl只有在成功打开新的句柄连接时,才会关闭默认的系统文件句柄。
用say来输出
- 输出内容并换行时,可以使用
say函数 - 这是perl 5.10的新特性,可以多试试
标量变量中的文件句柄
- 使用裸字和标量变量,根据需要进行选取
习题

第6章 哈希
什么是哈希?
名字之前有一个美元符号,之后有一个花括号- sv中的关联数组
访问哈希元素
$hash{$some_key}
访问整个哈希
- 用
%作为前缀,%hash
胖剪头
=>左边是键,右边是值;
哈希操作函数
keys和values
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
my @k = keys %hash;
my @v = values %hash;
my $count = keys %hash; # 返回键值对的个数
if(%hash) {
print "hash 不为空";
}
each函数
- 遍历哈希的每个键值对,可以使用
each,每次调用都会返回一个键,一个值
while (($key, $value) = each %hash) {
print "$key => $value\n";
}
- 一个推荐的函数
foreach $key (sort keys %hash){
$values = $hash($key);
print "$key => $value\n";
# 或者,可以略去额外的 $value 变量
# print “$key => $hash{$key}\n”;
}
哈希的典型应用
exists函数
- 检查哈希中是否存在某个键
if (exists $hash{"key"}){
# 存在
}
delete函数
- 直接删除指定的键和值。如果没有这样的键,那就结束,也不会出现警告或错误提示;
哈希元素内插
foreach $person (sort keys %books) {
if ($books{$person}) {
print "$person has $books{$person} items";
}
}
特殊哈希%ENV
- Perl会把环境信息放到特殊哈希
%ENV里面
习题

第7章 正则表达式
- regular expression
序列
$_ = "yabba dabba doo";
if (/abba/) {
print "It matched\n";
}
- 如上所示,两个斜线就是匹配操作符号!
动手实践不同模式
- 上面的小程序就够了
通配符
- 点号
.能匹配除换行外的任意单个字符
量词
- 指定匹配项的的重复次数。
- 最简单的量词是
?:前一个字符出现n次或0次 - 量词
*:前一个字符出现n次或0次,常用于匹配不固定长度的空白字符 .*:贪婪匹配,可以匹配任意非换行字符任意次
模式分组
- 用圆括号
( )将模式字符串分组 (.)\1:匹配连续出现的两个同样字符
择一匹配
|:或的关系
字符集
[a=z] # a到z的全部小写字母
[-a] # 连字符 或者 a
[^n-z] #不是n到z的字符
简写的反义形式
[a]的相反形式可以是[^a]
| 简写 | 匹配 |
|---|---|
| \d | 十进制数字 |
| \D | 非十进制数字 |
| \s | 空白字符 |
| \S | 非空白字符 |
| \h | 水平空白字符(Perl 5.10起支持) |
| \H | 非水平空白字符(Perl 5.10起支持) |
| \v | 纵向空白字符(Perl 5.10起支持) |
| \V | 非纵向空白字符(Perl 5.10起支持) |
| \R | 一般化的行结尾符号(Perl 5.10起支持) |
| \w | 单词字符 |
| \W | 非单词字符 |
| \n | 换行符(不是真正的简写) |
| \N | 非换行符(Perl 5.18 起属于稳定特性) |
Unicode字符属性
锚位
\A:匹配字符串的绝对开头\z:匹配字符串的绝对末尾\b:单词锚位,匹配单词边界
习题


第8章 用正则表达式进行匹配
用m//进行匹配
- 模式匹配操作符:
m( ),m< >,m{ },m[],其中选择斜线作为定界符时,一般省略前面的m,变成了/ /
模式匹配修饰符
用/i进行大小写无关的匹配
用/s匹配任意字符
/.*/s:可以匹配到换行符- 如果不习惯用
/s修饰符,可以使用[\D\d],[\S\s]等,原理就是数字字符以及非数字字符组合就是任意字符。
用/x加入辅助空白字符
- 使用这个之后,可以在模式里使用空格或换行使得代码可读性更高!
联合使用修饰符
- 单词匹配多想修饰符
if (/barney.*fred/is){# 同时使用 /i 和 /s
# 匹配成功
}
- 用花括号作为定界符,用vim就可以自动定位跳转
if (m{
barney
.*
fred
}isx){ # 或同时使用 /i 、 /s 和 /x
# 匹配成功
}
选择字符的解释方式
- Perl 5.14 开始增加了一些用于告诉Perl如何解释字符意义的修饰符,主要是:对大小写的处理以及对字符集合的阐释。
行首和行尾锚位
^与\A一样,$与\z一样- 如果加上
/m修饰符,/^/m就会匹配字符串开头和换行符之后的内容(就是每行开头)
绑定操作符=~
- 正则表达式默认匹配的目标文本是
$_,我们可以使用绑定操作操作符=~指定要匹配的目标文本。
捕获变量
- 捕获变量,把匹配到的内容用标量存储起来,方便调用!一般使用圆括号
()进行捕获
捕获变量的存续期
- 捕获变量的内容一般会保持到下次成功匹配为止,我们可以将其保存下来的;
禁用捕获的括号
- 在左括号后加上
?:,此时的括号仅用于分组,不再捕获匹配字符串。
命名捕获
- 使用如下的捕获标签,可以随意移动位置,并加入更多的捕获括号!
use v5.10;
my $names = 'Fred or Barney';
if ($names =~ m/(?<name1>\w+) (?:and|or)(?<name2>\w+)){
say "I saw $+{name1} and $+(name2)";
}
自动捕获变量
- $`:匹配保存之前的内容
- $&:匹配保存 的内容
- $’:匹配保存之后的内容
- 修饰符
/p可以对当前的表达式开启类似的自动捕获变量,变成了${^PREMATCH},${^MATCH},${^POSTMARTCH}
优先级
正则表达式优先级表
| 正则表达式特性 | 示例 |
|---|---|
| 元括号(分组或捕获) | (···),(?:···),(? |
| 量词 | a*,a+,a?,a{n,m} |
| 锚位和字符序列 | abc, ^, $, \A, \b,\z,\Z |
| 择一 | a|b|c |
| 原子 | a,[abc],\d,\l,\g{2} |
模式测试程序
#!/usr/bin/perl
while (<>) { # take one input line at a time
chomp;
if (/YOUR_PATTERN_GOES_HERE/) {
print "Matched: |$`<$&>$'|\n"; # the special match vars
} else {
print "No match: |$_|\n";
}
}
习题


第9章 用正则表达式处理文本
用s///进行替换操作
s/st1/st2; #试图将st1替换为st2
用/g进行全局替换
s/\s+/ /g; # 将任意连续的空白转换成单一空格
s/\A\s+//g; # 将开头的空白字符替换成空字符串
s/\s+\z//g; # 将结尾的空白字符替换成空字符串
s/\A\s+|\s+\z//g; #去除开头和结尾的空白字符
不同的定界符
- 和
m//和qw//一样,可以改变s///的定界符
替换操作的修饰符
- 除了
/g修饰符外,我们还可以把用在普通模式匹配中的/i、/x和/s修饰符用在替换操作中
绑定操作符
=~为s///指定不同的替换目标
非破坏性替换
- 如果需要同时保留原始字符串和替换后的字符串,该怎么办?
- 复制拷贝一份再替换
my $original = 'Fred ate 1 rib';
my $copy = $original;
$copy =~ s/\d+ ribs?/10 ribs/;
- 等价于
(my $copy = $original )=~ s/\d+ ribs?/10 ribs/;
- perl 5.14增加了一个
/r字符串,就会保留原来字符串中的值不变,把替换结果作为替换操作的返回值返回
use v5.14;
my $copy = $original =~ s/\d+ ribs?/10 ribs/r;
大小写转换
\U将它后面的所有字符转成大写的\L将它后面的所有字符转成小写的- 默认情况下,它们会影响之后全部的(替换)字符串,可以用
\E关闭大小写转换的功能; - 使用小写
\l和\u,它们只会影响紧随其后的第一个字符; - 同时使用
\u与\L来表示"后续字符全部转为小写的,但首字母大写”
元字符转义
s/\(\(\(Fred/fred/
# 使用\Q简化形式
s/\Q(((Fred/fred/
\
split操作符
- 格式如下:
my @fields = split /separator/, $string;
- 例子如下:
- 注意第二行和第三行
my @fields = split /:/,"abc:def:g:h"; # 得到("abc","def","g","h")
my @fields = split /:/,":::a:b:c:::" # 得到("","","","a","b","c")
my @fields = split /:/,":::a:b:c:::",-1 # 得到("","","","a","b","c","","","")
- 默认
split会以空白字符分割$_中的字符串;
my @fields = split; # 基本等效于split /\s+/, $_;
join函数
- join会把胶水涂进每个片段之间并返回结果字符串
my $x = join ":",4,6,8,10,12; # $x 为 “4:6:8:10:12”
my @values = split /:/,$x; # @values 为(4,6,8,10,12)
my $z = join "-", @values; # $z为 “4-6-8-10-12”
列表上下文中的m///
更强大的正则表达式
习题


第10章 其他控制结构
unless控制结构
if条件为真时执行,unless条件为假时执行
伴随unless的else语句
- 就是
if else改成了unless else
until控制结构
- 颠倒while的条件表达式,就用
until
表达式修饰符
- 简化代码书写
- 即使条件表达式写在后面,它也会先执行
- 倒装句
print "$n is a negative number.\n" if $n < 0;
if($n < 0) {
print "$n is a negative number.\n";
}
裸块控制结构
{ }主要是为变量限制作用域,和c++一样
elsif子句
- 注意不是
elseif
自增与自减
- 前置后置,自增自减。
for控制结构
- 和c语言写法一致
for和foreach之间的秘密
- for和foreach实际上是等价的。括号中有两个分号,就把它当做
for,若没有分号,就把他当做foreach
循环控制
last操作符
- 和c语言的break一样,退出循环
next操作符
- 和c语言的continue一样,跳过本次循环
redo操作符
- 这不是goto语句封装好的吗?
带标签的块
- 这不就是verilog中的程序块别名吗?
条件操作符
- 三目运算符
? : expression ? if_true_expr : if_false_expr
逻辑操作符
- 全套的逻辑操作符
短路操作符的返回值
短路操作符可以改为三目运算符!
使用部分求值操作符的控制结构
&&、||、//、?:都是根据左边的值确定要不要执行右边的表达式
习题


第11章 Perl模块
- 如何使用现有的模块,目的是熟悉使用CPAN完成自己的任务!
寻找模块
- 寻找那些没有随Perl发布的模块,可以到CPAN Seach网站(http://search.cpan.org)或MetaCPAN(http://www.metacpan.org)
安装模块




使用简易模块
习题

第12章 文件测试
文件测试操作符
stat和lstat函数
loacltime函数
位运算操作符
习题


第13章 目录操作
当前工作目录
- 借助标准模块之一
Cwd模块,查看当前的工作目录是哪个
use v5.10;
use Cwd;
say "The current working directory is ",getcwd();
- 可以使用标准模块之一
File::Spec实现相对路径和绝对路径之间的相互转换\
修改工作目录
chdir:和shell中的cd一个意思
chdir '/etc' or die "cannot chdir to /etc :$!";
- 可以使用
File::HomeDir模块去往特定用户的主目录,他支持大部分操作系统。
文件名通配
- 文件名通配:
glob
my @all_file = glob '*';
my @pm_file = glob '*.pm';
- Perl内置的
glob并非唯一选择,我们可以用File::Glob模块提供各式兼容和扩展的文件名通配。
文件名通配的隐式语法
my @all_files = <*>; # 效果和这样的写法完全一致: my @all_files = glob "*";
- Perl 会把尖括号内出现的变量替换成它的值,类似于双引号内字符串的变量内插,如下
my $dir = '/etc';
my @dir_file = <$dir/* $dir/.*>;
目录句柄
- 一个例子
my $dir_to_process = '/etc';
opendir my $dh, $dir_to_process or die "Cannot open $dir_to_process:$!";
foreach $file (readdir $dh) {
print "one file in $dir_to_process is $file\n";
}
closedir $dh;
- 使用裸字
DIR
my $dir_to_process = '/etc';
opendir DIR, $dir_to_process or die "Cannot open $dir_to_process:$!";
foreach $file (readdir DIR) {
print "one file in $dir_to_process is $file\n";
}
closedir DIR;
文件和目录的操作
删除文件
unlink:
unlink 'slate', 'bedrock','lava';
unlink qw{slate bedrock lava};
unlink glob '*.o';
unlink返回的是成功删除的文件数目,我们可以把他们放到循环依次删除并检查
foreach my $file (qw(slate bedrock lava)) {
unlink $file or warn "failed on $file:$!\n";
}
重命名文件
rename 'old','new';- 借用胖剪头
=>: - 如何批量把名称是
.old结尾的文件改名为以.new结尾?
foreach my $file (glob "*.old") {
my $newfile = $file;
$newfile =~ s/\.old$/.new/;
if (-e $newfile) {
warn "can't rename $file to $newfile: $newfile exists\n"
} elsif(rename $file => $newfile) {
# 改名成功,什么都不需要做
} else {
warn "rename $file to $newfile failed:$!\n";
}
}
- 循环里的前两行还可以修改为
my ($newfile = $file) =~ s/\.old$/.new/;
- 也可以在Perl 5.14里面加上
/r修饰符,
use v5.14;
my $newfile = $file =~ s/\.old$/.new/r;
链接与文件
- 与Linux操作系统的文件作对比吧,inode节点等,确定是
软链接这个说法吗?(之前有老师强调过,没有软链接这一说,是符号链接和硬链接)
创建和删除目录
- 创建失败返回设定值
mkdir 'fred', 0755 or warn "Cannot make fred directory: $!";
- 移除空目录
foreach my $dir(qw{fred barney betty}) {
rmdir $dir or warn "cannot rmdir $dir:$!\n";
}
- 如果要创建临时目录或文件,可以用
File::Temp模块
修改权限
chmod不支持linux中a+x这种格式,除非从CPAN安装了File::chmod.- 常规格式如下:
chmod 0755, 'fred','barney';
修改文件属主
chown $user, $group, glob '*.o';
修改时间戳
my $now = time;
my $ago = $now - 24 * 60 * 60; # 一天的秒数
utime $now, $ago, glob '*'; # 将最后访问时间改为当前时间,最后修改时间改为一天前
习题


第14章 字符串与排序
用index查找子字符串
my $where = index($stuff, "wor");
用substr操作子字符串
my $part = substr($string,$initial_position, $length);
用sprintf格式化字符串
my $money = sprintf "%.2f", 2.4997;
高级排序
- 飞碟操作符’<=>’
my @descending = sort {$b <=> $a} @some_numbers;
按哈希值排序
my %score = ("barney" => 195, "fred" => 205, "dino" => 30);
my @winners = by_score keys %score;
按多个键排序
- 例子1:
my %score = (
"barney" => 195, "fred" => 205,
"dino" => 30, "bamm-bamm" => 195,
);
my @winners = by_score_and_name keys %score;
sub by_score_and_name {
$score{$b} <=> $score{$a} #先按照分数降序排列
or
$a cmp $b #分数相同的再按名字的ASCII码序排列
} @winners
- 例子2:
@patron_IDs = sort{
&fines($b) <=> &fines($a) or
$items($b) <=> $items($a) or
$family_name{$a} cmp $family_name{$b} or
$personal_name{$a} cmp $family_name{$b} or
$a <=> $b;
} @patron_IDs;
习题

第15章 进程管理
习题


第16章 高级Perl技巧
习题

后记
- 本文内容只是记录了小编想学习的部分,其他部分暂时忽略。
- 要是工作中需要的话,再深究!
版权声明:本文为haojie_duan原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。