perl栏分为perl基本语法、高阶语法、和一个perl自动化脚本生成器案例。
语法部分是笔者学习perl的总结,并非原创。
案例是笔者原创。
perl 高阶语法
Contents
高阶语法
语法
print “”; # 打印内容到默认终端
print HANDLE “cmd”; # 打印cmd内容到文件句柄HADNLE指向的地址
print $handle_file <HANDLE>; # 将文件句柄HANDLE指向的地址内容写到变量文件句柄$handle_file指向的地址中
将内容打印到句柄HANDLE指向的终端处,print将内容输出到显示终端是一种特殊形式
文件句柄
Perl进程与外界之间的IO联系的名称,在Perl5.6之前,所有文件句柄名称都是裸子,之后可以把文件句柄的引用放在常规变量中。6个特殊文件句柄名是Perl保留的,STDIN、STDOUT、STDERR、DATA、ARGV、ARGVUT。
打开文件句柄
三种perl默认文件句柄---STDIN、STDOUT、STDERR,是产生Perl进程的父进程自动打开的文件或设备。
open Filehandler,filename;
示例:
open CONFIG,'dino'; #打开已存在的dino文件,文件中的任何内容都可以读到我们的程序中
open CONFIG,'<dino'; #用小于号声明该文件只是用来读入,而非写入
open BEDROCK,‘>fred’; #大于号,打开文件句柄,并输出到新文件fred中,如果已存在fred,则清除原内容并以新内容取代之;
open LOG,'>>logfile'; #双大于号,打开文件,如果文件原本就存在,那么新数据会添加在原有内容后面,如果不存在,会创建一个新文件。
open CONFIG,'<','dino';
open BEDROCK,'>',$file_name;
open LOG,'>>','logfile';
open CONFIG,'<:encoding(UTF-8)','dino'; ##open CONFIG,'<:utf8','dino';
标量变量中的文件句柄
示例:
my $rocks_fh;
open $rocks_fh,'<','rocks.txt' or die "Could not open rocks.txt:$!";
while(<rocks_fh>){
chomp;
....
}
close $rocks_fh;
返回文件句柄
1、使用\*
#!/usr/bin/perl
use strict;
sub openfile()
{
my $path=shift;#把数组的第一个值移出并返回它,然后把数组长度减一并把所有的东西都顺移
open(FILE,"$path") or die "Can't open $path $!\n ";
return \*FILE;
}
my $temp=&openfile("config");
my @file=<$temp>;
print @file;
2、使用变量
示例:
#!/usr/bin/perl
use strict;
sub openfile()
{
my $file;
my $path=shift;
open($file,"$path") or die "Can't open $path $!\n ";
#close($file);
return $file;
}
my $temp=&openfile("config");
my @file=<$temp>;
print @file;
glob函数
描述
此函数返回与EXPR匹配的文件的列表,这些文件将由标准Bourne shell进行扩展。如果EXPR未指定路径,请使用当前目录。如果省略EXPR,则使用$_的值。
从Perl 5.6开始,扩展是在内部完成的,而不是使用外部脚本。扩展遵循csh(以及任何派生形式,包括tcsh和bash)的扩展方式,其翻译如下:
- 以单个句点开头的文件将被忽略,除非EXPR明确匹配。
- *字符与零个或多个任何类型的字符匹配。
- 的?字符匹配任何类型的一个字符。
- [..]构造与正则表达式匹配列出的字符,包括范围。
- 〜字符与主目录匹配; 〜name与用户名的主目录匹配。
- {..}构造与括号内的任何逗号分隔的单词匹配。
语法
以下是此函数的简单语法
glob EXPR
glob
返回值
此函数在错误时返回undef,否则在标量context中返回扩展名列表中的第一个文件,在错误时返回空列表,否则返回列表context中扩展名的列表。
例
以下是显示其基本用法的示例代码-
#!/usr/bin/perl
(@file_list) = glob "perl_g*";
print "Returned list of file @file_list\n";
执行上述代码后,将产生以下输出-
Returned list of file
glob相当于shell中的通配符,有2种形式:
1.@files = glob "*.pl";
2.@files = <*.pl>;perl检查<>中是否是句柄,不是则当成glob处理;
#my @file = glob "~/Proj/Perl/*.pl"; #与下句相同
my @file = <~/Proj/Perl/*.pl>;
#my $filestr = "~/Proj/Perl/*.pl"; #<>处理含通配符的变量时,变量需要加{},否则$filestr>会当成变量名
#my @file = <${filestr}>;
foreach(@file){
print $_."\n";
}
perl regular expression
Perl语言的正则表达式功能非常强大,基本上是常用语言中最强大的,很多语言设计正则式支持的时候都参考Perl的正则表达式。
形式
Perl的正则表达式的三种形式,分别是匹配,替换和转化:
匹配
:m//(还可以简写为//,略去m)
替换
:s///
转化
:tr///
这三种形式一般都和 =~ 或 !~ 搭配使用, =~ 表示相匹配,!~ 表示不匹配。
模式匹配修饰符
模式匹配有一些常用的修饰符,如下表所示:
修饰符 | 描述 |
i | 忽略模式中的大小写 |
m | 多行模式 |
o | 仅赋值一次 |
s | 单行模式,"."匹配"\n"(默认不匹配) |
x | 忽略模式中的空白 |
g | 全局匹配 |
cg | 全局匹配失败后,允许再次查找匹配串 |
正则表达式变量
perl处理完后会给匹配到的值存在三个特殊变量名:
- $`: 匹配部分的前一部分字符串
- $&: 匹配的字符串
- $': 还没有匹配的剩余字符串
如果将这三个变量放在一起,你将得到原始字符串
示例:
#!/usr/bin/perl
$string = "welcome to runoob site.";
$string =~ m/run/;
print "匹配前的字符串: $`\n";
print "匹配的字符串: $&\n";
print "匹配后的字符串: $'\n";
结果:
匹配前的字符串: welcome to
匹配的字符串: run
匹配后的字符串: oob site.
替换操作符
替换操作符 s/// 是匹配操作符的扩展,使用新的字符串替换指定的字符串。基本格式如下:
s/PATTERN/REPLACEMENT/;
替换操作修饰符如下表所示:
修饰符 | 描述 |
i | 如果在修饰符中加上"i",则正则将会取消大小写敏感性,即"a"和"A" 是一样的。 |
m | 默认的正则开始"^"和结束"$"只是对于正则字符串如果在修饰符中加上"m",那么开始和结束将会指字符串的每一行:每一行的开头就是"^",结尾就是"$"。 |
o | 表达式只执行一次。 |
s | 如果在修饰符中加入"s",那么默认的"."代表除了换行符以外的任何字符将会变成任意字符,也就是包括换行符! |
x | 如果加上该修饰符,表达式中的空白字符将会被忽略,除非它已经被转义。 |
g | 替换所有匹配的字符串。 |
e | 替换字符串作为表达式 |
转化操作符
以下是转化操作符相关的修饰符:
修饰符 | 描述 |
c | 转化所有未指定字符 |
d | 删除所有指定字符 |
s | 把多个相同的输出字符缩成一个 |
以下实例将变量 $string 中的所有小写字母转化为大写字母:
示例:
#!/usr/bin/perl
$string = 'welcome to runoob site.';
$string =~ tr/a-z/A-Z/;
print "$string\n";
更多示例:(会用会很好用^</>^)
$string =~ tr/\d/ /c; # 把所有非数字字符替换为空格
$string =~ tr/\t //d; # 删除tab和空格
$string =~ tr/0-9/ /cs # 把数字间的其它字符替换为一个空格。
更多正则表达式规则
表达式 | 描述 |
. | 匹配除换行符以外的所有字符 |
x? | 匹配 0 次或一次 x 字符串 |
x* | 匹配 0 次或多次 x 字符串,但匹配可能的最少次数 |
x+ | 匹配 1 次或多次 x 字符串,但匹配可能的最少次数 |
.* | 匹配 0 次或多次的任何字符 |
.+ | 匹配 1 次或多次的任何字符 |
{m} | 匹配刚好是 m 个 的指定字符串 |
{m,n} | 匹配在 m个 以上 n个 以下 的指定字符串 |
{m,} | 匹配 m个 以上 的指定字符串 |
[] | 匹配符合 [] 内的字符 |
[^] | 匹配不符合 [] 内的字符 |
[0-9] | 匹配所有数字字符 |
[a-z] | 匹配所有小写字母字符 |
[^0-9] | 匹配所有非数字字符 |
[^a-z] | 匹配所有非小写字母字符 |
^ | 匹配字符开头的字符 |
$ | 匹配字符结尾的字符 |
\d | 匹配一个数字的字符,和 [0-9] 语法一样 |
\d+ | 匹配多个数字字符串,和 [0-9]+ 语法一样 |
\D | 非数字,其他同 \d |
\D+ | 非数字,其他同 \d+ |
\w | 英文字母或数字的字符串,和 [a-zA-Z0-9_] 语法一样 |
\w+ | 和 [a-zA-Z0-9_]+ 语法一样 |
\W | 非英文字母或数字的字符串,和 [^a-zA-Z0-9_] 语法一样 |
\W+ | 和 [^a-zA-Z0-9_]+ 语法一样 |
\s | 空格,和 [\n\t\r\f] 语法一样 |
\s+ | 和 [\n\t\r\f]+ 一样 |
\S | 非空格,和 [^\n\t\r\f] 语法一样 |
\S+ | 和 [^\n\t\r\f]+ 语法一样 |
\b | 匹配以英文字母,数字为边界的字符串 |
\B | 匹配不以英文字母,数值为边界的字符串 |
a|b|c | 匹配符合a字符 或是b字符 或是c字符 的字符串 |
(abc) | 匹配含有 abc 的字符串 (pattern) () 这个符号会记住所找寻到的字符串,是一个很实用的语法.第一个 () 内所找到的字符串变成 $1 这个变量或是 \1 变量,第二个 () 内所找到的字符串变成 $2 这个变量或是 \2 变量,以此类推下去. |
/pattern/i | i 这个参数表示忽略英文大小写,也就是在匹配字符串的时候,不考虑英文的大小写问题. \ 如果要在 pattern 模式中找寻一个特殊字符,如 "*",则要在这个字符前加上 \ 符号,这样才会让特殊字符失效 |
反向引用
表达式:
(.)(..)\1\2\1
(.):任意一个字符
(..)任意两个字符
\1:表示第一个任意字符,即和(.)相同
\2:表示第二个任意字符,即和(..)相同
\1:表示第一个任意字符,即和(.)相同
[\t\n\r\f]=\s 空格
[^\s]=\S 非空格
[\d\D] 任意字符(包括换行符\n)
捕获变量()
捕获变量使用$1/$2/$3…等特殊变量
$_="hello there,neighbor";
if(/\s(\w+),/){
print $1;#-->小括号捕获到的变量,$1为特殊变量,一般有几个小括号就有几个$
}
if(/(\S+) (\S+), (\S+)/){
print "$1 $2 $3\n";#-->捕获到的三个变量
}
只分组不捕获(?:)
小括号只用于分组不用于捕获时:(?:)
示例:
$_="hello there,neighbor";
if(/(?:\S+) (\S+), (\S+)/){
print "$1 $2 $3\n";#-->现在$1=there;$2=neighbor,$3为未定义
}
捕获变量命名(?<>)
捕获变量命名(?<user_name>),用户命名在一个特殊哈希%+中
$_="hello there,neighbor";
if(/(?:\S+) (?<name1>\S+), (?<name2>\S+)/){
print "$+{name1},$+{name2}\n";
}#-->自定义命名的变量存在特殊哈希%+中
反向引用\g<>或\k<>
my $names="fred gates and wilma gates";
if($names=~/(?<last_name>\w+) and \w+ \g<last_name>/){
print "$+{last_name}\n";
}
表达式文本可用符号
符号 含义
\U 将匹配到的字符串所有字母变为大写
\L 将匹配到的字符串所有字母变为小写
\E 结束\U\L的作用范围
\u 将匹配到的字符串的第一个字母变为大写
\l 将匹配到的字符串的第一个字母变为小写
\u\L 匹配到的字符串的第一个字母为大写,其余字母为小写
应用
省略匹配变量
在if条件中可以使用简化匹配格式,省略上文中的$_变量
if(/^\s*\//){cmd;}
表示:上文中变量$_是否可以匹配上表达式’^\s*\/’
模块
localtime模块
示例:
$time = localtime();
print "\$time: $time\n";
结果:
$time: Thu Aug 1 03:12:14 2024
此处,不能直接使用print localtime()来输出时间,会得不到上结果
scalar(localtime)
示例:
perl -e 'print scalar(localtime),"\n"'
结果
Tue Aug 13 23:44:40 2024
时间格式化输出
localtime函数,根据它所在的上下文,可以用两种完全不同的方法来运行。在标量上下文中,localtime函数返回一个格式化很好的当前时间字符串。例如,print scalar (localtime)这个代码,它输出的结果将类似于Thu Sep 16 23:00:06 1999。在列表上下文中,localtime将返回能够描述当前时间的一个元素列表:
my($sec,$min,$hour,$mday,$mon,$year_off,$wday,$yday,$isdat) = localtime;
字段 值
$sec 秒,0 ~ 59
$min 分,0 ~ 59
$hour 时,0 ~ 23
$mday 月份中的日期, 1 ~ 2 8、2 9、3 0或3 1
$mon 年份中的月份, 0 ~ 11(这里请特别要小心)
$year_off 1900年以来的年份。将1900加上这个数字,得出正确的4位数年份
$wday 星期几,0 ~ 6
$yday 一年中的第几天,0 ~ 364或365
$isdst 如果夏令时有效,则为真
示例:
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = (localtime);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = (
sprintf("%02d", $sec),
sprintf("%02d", $min),
sprintf("%02d", $hour),
sprintf("%02d", $mday),
sprintf("%02d", $mon + 1),
sprintf("%04d", $year + 1900),
sprintf("%00d", $wday + 1),
sprintf("%03d", $yday + 1),
$isdst
);
print "$isdst-$yday-$wday $year-$mon-$mday $hour:$min:$sec\n";
模块stat
定义
案例
stat函数获取文件的元数据信息,它们都会发起stat系统调用,stat函数返回共13项属性信息,这13项属性先后顺序分别是
use 5.010;
$filename=$ARGV[0]; # 第一个参数,这里使用一个file
my @arr = ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks)
= stat($filename);
say '$dev :',$arr[0];
say '$inode :',$arr[1];
say '$mode :',$arr[2];
say '$nlink :',$arr[3];
say '$uid :',$arr[4];
say '$gid :',$arr[5];
say '$rdev :',$arr[6];
say '$size :',$arr[7];
say '$atime :',$arr[8];
say '$mtime :',$arr[9];
say '$ctime :',$arr[10];
say '$blksize :',$arr[11];
say '$blocks :',$arr[12];
结果是:
$dev :2050
$inode :67326520
$mode :33188
$nlink :1
$uid :0
$gid :0
$rdev :0
$size :12
$atime :1533544992
$mtime :1533426824
$ctime :1533426824
$blksize :4096
$blocks :8
属性 | 含义 |
dev | 文件所属文件系统的设备ID |
inode | 文件inode号 |
mode | 文件类型和文件权限(两者都是数值表示) |
nlink | 文件硬链接数 |
uid | 文件所有者的uid |
gid | 文件所有者的gid |
rdev | 文件的设备ID(只对特殊文件有效,即设备文件) |
size | 文件大小,单位字节 |
atime | 文件atime的时间戳(从1970-01-01开始计算的秒数) |
mtime | 文件mtime的时间戳(从1970-01-01开始计算的秒数) |
ctime | 文件ctime的时间戳(从1970-01-01开始计算的秒数) |
blksize | 文件所属文件系统的block大小 |
blocks | 文件占用block数量(块大小一般是512字节,可通过stat -c "%B"命令获取块大小) |
需要注意的是,$mode返回的是文件类型和文件权限的结合体,且文件权限并非直接的8进制权限值,要计算出Unix系统中直观的权限数值(如0755、0644),需要和0777做位与运算。
模块File::Spec
示例
### sub get_path_dir_name ###
sub get_path_dir_name{
my $file = shift @_; # 此处不要只用@_,否则my $file会为1,即@_的元素个数1
print "\n1:$file 1:@_\n";
my $file_abs = File::Spec->rel2abs($file);
print "\n2:$file_abs\n";
my (undef, $path_name, $folder_name) = File::Spec->splitpath($file_abs); #此处返回的第一个参数可以不用关注,使用undef
print "\n3:undef $path_name $folder_name\n";
return ($folder_name,$path_name);
} # endof subroutine get_path_dir_name
my $file = $ARGV[0]; # 命令行中第一个参数为$ARGV[0],下标从0开始,$0表示脚本名
my ($folder_name,$path_name) = &get_path_dir_name($file);
print " (\$folder_name,\$path_name) = ($folder_name,$path_name) ";
print "\n";
执行:
~/perl_tra/sign_reference.pl /proj/sbio_redang_dft2/weifexie/sbiodft_krn1usb4HC0HC1_MTO_0416/SCAN_ATPG/sata_fch_usb4_container_atpg_sim/Krackan_1/usb4_sc0_t/containe
结果:
1:/proj/sbio_redang_dft2/weifexie/sbiodft_krn1usb4HC0HC1_MTO_0416/SCAN_ATPG/sata_fch_usb4_container_atpg_sim/Krackan_1/usb4_sc0_t/containe 1:
2:/proj/sbio_redang_dft2/weifexie/sbiodft_krn1usb4HC0HC1_MTO_0416/SCAN_ATPG/sata_fch_usb4_container_atpg_sim/Krackan_1/usb4_sc0_t/containe
3:undef /proj/sbio_redang_dft2/weifexie/sbiodft_krn1usb4HC0HC1_MTO_0416/SCAN_ATPG/sata_fch_usb4_container_atpg_sim/Krackan_1/usb4_sc0_t/ containe
($folder_name,$path_name) = (containe,/proj/sbio_redang_dft2/weifexie/sbiodft_krn1usb4HC0HC1_MTO_0416/SCAN_ATPG/sata_fch_usb4_container_atpg_sim/Krackan_1/usb4_sc0_t/)
在perl脚本中使用shell的命令
system “shell command argument …”
辨析print、say、sprintf、printf
可以查看perl用户手册
perldoc -f print
perldoc -f printf
perldoc -f sprintf
print、printf和say都可以输出信息。print和say类似,print不自带换行符,say自带换行符,但要使用say,必须写use语句use 5.010;,printf像C语言的printf一样,可以定制输出格式。
perl中有上下文的概念,这几个输出操作也同样有上下文环境:列表上下文
@arr=qw(hello world);
print "hello world","\n";
print "hello world\n";
print @arr; # 输出helloworld(没空格)
print "@arr"; # 输出hello world(有空格)
say
use 5.010;
say "hello world!"; # 自带换行符
print/say可以以函数格式(print(args)/say(args))进行输出,这时候有个陷阱需要注意:
print(3+4)*4;
这个返回7,而不是28。这是怎么计算的?
Perl中很多时候是可以省略括号的,这往往让我们忘记括号的归属。而Perl中又有上下文的概念,在不同上下文执行同一个操作的结果是不一样的。在这里:
- print后内容不加括号的时候,它需求的参数是一个列表上下文,它后面的所有内容都会被print输出
- print后内容加括号的时候,它只会输出括号中的内容
所以,上面的语句等价于
(print(3+4))*4;
它先执行print(7),然后拿到print的返回值1,将其乘以4,由于没有赋值给其它变量,所以这个乘法的结果被丢弃。
如果将上面赋值给一个变量;
$num = print(3+4)*4;
该处$num的值就是4.
printf
常用:
printf FORMAT, LIST
printf FILEHANDLE FORMAT, LIST
不常用(主要是因为隐含的细节,会导致阅读上的障碍吧):
printf FILEHANDLE
sprintf
用于调整需打印的文本格式、变量格式
命令格式,只有一种:
sprintf FORMAT, LIST
区别
command description
print 打印信息,可以输出到文件里
printf 可以整理信息的格式,可以输出到文件里。与sprintf类似,区别是可以打印
sprintf 可以整理信息的格式。与printf类似,区别是仅仅用于字符串的格式化,没有任何print效果
比如:
$result = sprintf("%08d",$number);让$number有8个前导零。
$rounded = sprintf("%.3f",$number);
让小数点后有3位数字。
sprintf允许的如下常用的转换:
%% 百分号
%c 把给定的数字转化为字符
%s 字符串
%d 带符号整数,十进制
%u 无符号整数,十进制
%o 无符号整数,八进制
%x 无符号整数,十六进制
%e 浮点数,科学计算法
%f 浮点数,用于固定十进制计数
%g 浮点数,包括%e和%f
ARGV说明
@ARGV数组
这个数组包含了传递给脚本的所有额外参数
perl命令行的参数列表放进数组ARGV(@ARGV)中。既然是数组,就可以访问($ARGV[n])、遍历,甚至修改数组元素ARGV数组索引从0开始计算,索引0位从脚本名(perl程序名)之后的参数开始计算,即使这个参数是perl的选项默认,这些命令行参数是perl程序的数据输入源,也就是perl会依次将它们当作文件进行读取
参数是有序的,读取的时候也是有序的
需要区分ARGV变量和ARGV数组:
$ARGV表示命令行参数代表的文件列表中,钻石操作符正在读取的文件名,符号<>内读入的是文件句柄,没有内容时默认是ARGV句柄,ARGV句柄指向@ARGV的各个元素,
@ARGV表示命令行参数数组
$ARGV[n]:表示命令行参数数组的元素
和C一样,PERL也有存储命令行参数的数组@ARGV,可以用来分别处理各个命令行参数;与C不同的是,$ARGV[0]是第一个参数,而不是程序名本身。
$var = $ARGV[0]; # 第一个参数
$numargs = @ARGV; # 参数的个数
PERL中,<>操作符实际上是对数组@ARGV的隐含的引用,其工作原理为:
1、当PERL解释器第一次看到<>时,打开以$ARGV[0]为文件名的文件;
2、执行动作shift(@ARGV); 即把数组@ARGV的元素向前移动一个,其元素数量即减少了一个。
3、<>操作符读取在第一步打开的文件中的所有行。
4、读完后,解释器回到第一步重复。
例:
@ARGV = ("myfile1", "myfile2"); #实际上由命令行参数赋值
while ($line = <>) { # <> 默认的指针是指向参数行列表中元素(文件)
print ($line);
}
将把文件myfile1和myfile2的内容打印出来。
perl用来解析@ARGV的模块
Getopt::Std和Getopt::Long
Getopt::Std是Perl的一个核心模块,提供了简单的接口来解析单字符选项
ARGV数组的元素可以通过索引访问,索引从0开始,$ARGV[0]、$ARGV[1]…
Ⅰ、对于需要支持长选项或者更复杂选项的场景,Getopt::Long模块是更好的选择
示例:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my $verbose;
my $output_file;
GetOptions(
'verbose' => \$verbose,
'output=s' => \$output_file,
);
if ($verbose) {
print "Verbose mode enabled\n";
}
if ($output_file) {
print "Output will be saved to $output_file\n";
}
Ⅱ、需要实现更复杂的逻辑,比如参数的默认值、互斥选项、参数的重复等
示例:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my $input_file = “./input_file.txt”;
my %opts;
GetOptions(
'help|?' => sub { usage() },
'config=s' => \$opts{config},
'verbose+' => \$opts{verbose},
'port=i' => \$opts{port},
‘debug’ => \$debug,
‘default’ =>
{‘input_file=s’=> ‘./input_file.txt’
}
) or die “Error in command line arguments”;
sub usage {
die "Usage: $0 [--config FILE] [--verbose] [--port PORT]\n";
}
Ⅲ、在解析参数后,验证参数的有效性并处理错误是必不可少的步骤
if ($opts{port} && $opts{port} !~ /^\d+$/) {
die "Invalid port number: $opts{port}\n";
}
关于Getoptions函数的补充说明
接受一个哈希表作为参数,其中键是选项的名称,值是一个引用,指向存储选项值的变量。
例如,"debug" => \$debug 表示将 --debug 选项的值存储在 $debug 变量中。如果选项后面没有值,则变量将被设置为 1。
GetOptions 函数还可以接受一些选项,用于指定默认值、验证选项值等。例如,可以使用 default 选项指定选项的默认值。
在Perl中,你可以使用标准模块Getopt::Long来解析命令行选项(Command Line Options)。Getopt::Long模块允许你定义命令行选项以及它们的值,并且还可以处理各种类型的选项,如标志选项(flag options)和带有参数的选项。
以下是一个简单的示例,展示了如何在Perl中使用Getopt::Long模块来处理命令行选项:
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
my $input_file;
my $output_file;
my $verbose;
# 定义命令行选项以及它们的值
GetOptions(
"input=s" => \$input_file, # 带有参数的选项,使用"s"表示字符串
"output=s" => \$output_file, # 带有参数的选项,使用"s"表示字符串
"verbose" => \$verbose, # 标志选项,没有参数
) or die "Error in command line arguments.\n";
# 检查选项是否正确解析
if ($verbose) {
print "Verbose mode is enabled.\n";
}
if ($input_file) {
print "Input file: $input_file\n";
}
if ($output_file) {
print "Output file: $output_file\n";
}
假设以上脚本保存为script.pl。你可以通过在命令行中输入类似以下的命令来运行它:
perl script.pl --input input.txt --output output.txt --verbose
这个脚本将会解析命令行选项,并根据传递的参数输出结果。在上面的示例中,我们定义了三个选项:–input、–output 和 --verbose。其中,–input和–output是带有参数的选项,而–verbose是一个标志选项(没有参数,只需要出现与否来表示是否启用)。
Getopt::Long模块将在运行脚本时解析命令行参数,并将对应选项的值赋给我们定义的变量。注意,如果用户提供了无效的选项或选项值,Getopt::Long会返回0,此时我们使用or die语句来输出错误信息并终止脚本的执行。
总之,Getopt::Long模块为Perl脚本提供了一个方便且灵活的方式来处理命令行选项。
perl模块 Getopt::Long解析参数
Getopt::Long模块是用于解析命令行参数的perl模块
选项解析
其他用法
使用options调用subroutines
多命名选项
捆绑选项
- 和
GetoptLongConfigure
## option variables with default value
my $verbose = "";
my $nda = "";
my $more = 0;
my $value = "";
my @libs = ();
my %defines = ();
## parse options from @ARGV
GetOptions(
'verbose' => \$verbose,
'nda!' => \$nda,
'more+' => \$more,
'tag=s' => \$tag,
'value:s' => \$value,
'libs=i' => \@libs, ## 'libs=i@' => \$libs,
'define=s' => \%defines, ## 'define=s%' => \$defines,
) or die $!;
选项解析
verbose,只有单独的一个选项,不接受任何参数。在命令行用--verbose来触发,触发后$verbose被设置为1,次用法常作为一个开关选项使用。
nda!,该选项在nda后加一个!,表示可以接受--nda和--nonda两个选项,对应的将$nda设置为1和0,如果触发该选项,$nda值为""(即空值),可以用perl内置函数length检测$nda。
more+该选项的+表示在参数列表每出现一次--more,对应的变量$more自加1。
tag=s该选项必须接受一个string参数,=表明必须要接受一个参数,s表明参数为任意字符串,也可用i或f指明参数为整数或浮点数。
value:s与tag=s的唯一区别是:,表明不是必须接受一个参数,可以--value形式调用,s默认赋值为"",i/f默认赋值为0。
|: "help|h|?" => \my $help,
?:
表示或者。
libs=i指定一个数组引用@libs,表明可以多次使用"--libs <lib>"获取多个值并存到数组中,也可以使用另一种形式'libs=i@' => \$libs,如果要使用"--libs <lib1> <lib2> <lib3>"这种参数调用形式,在GetOptions()中使用'libs=i{3}' => \@libs指定每次传入3个值。可以试试'libs=i{1,}' => \@libs。
define=s指定一个hash引用%defines,用--define os=linux传入一个hash参数。其他特点同上一个段落。
其他用法
使用options调用subroutines
my $verbose = "";
GetOptions(
'set' => \&handle,
) or die $!;
sub handle {
$verbose = 100;
print "options \'--set\' set verbose $verbose\n";
}
多命名选项
GetOptions('length|height' => \$length);
1
捆绑选项
ex: ls -al
## 用法1
use Getopt::Long;
Getopt::Long::Configure("bundling"); ## **配置选项**
my $long = "";
my $all = "";
my $al = "";
GetOptions(
'long|l' => \$long, # 此处必须显式的指定'l'为'long'的aliase
'all|a' => \$all, # 此处必须显式的指定'a'为'all'的aliase
'al' => \$al,
) or die $!;
## 现在命令行可使用 '-al'选项,同时设置$long/$all为1.**single dash**
## 使用'--al'选项设置$al为1.**double dash**
## 用法2
use Getopt::Long;
Getopt::Long::Configure("bundling_override"); ## **配置选项**
my $long = "";
my $all = "";
my $al = "";
GetOptions(
'long|l' => \$long, # 此处必须显式的指定'l'为'long'的aliase
'all|a' => \$all, # 此处必须显式的指定'a'为'all'的aliase
'al' => \$al,
) or die $!;
## 现在不可以使用 '-al'选项设置$long/$all,'-al'和'--al'的作用是一样;
## 不过仍然能使用bundling,因为有长选项'--al'存在,所以捆绑选项'-al'被override;
## 如果没有长选项'--al','-al'仍然与方法1中的作用一样。
## 在用法一和用法二中,如果'long|l=i' => \$long,'all|a=i' => \$all,
## 即$long/$all都需要一个整数作为参数,那么可使用'-l11a22'实现'length=11''all=22'的效果
#用法3
use Getopt::Long;
Getopt::Long::Configure("bundling_values");
...
GetOptions(
...
) or die $!;
## 只有'-l11'或者'-a22'可以使用,'-l11a22'和'-al'等方式都不能用
## 用法4
use Getopt::Long;
Getopt::Long::Configure("bundling", "ignorecase_always");
...
## 当使用Configure的'bundling'配置时,短名称如'-a/-l'都是大小写敏感,
## 而长名称对大小写不敏感,所以使用"ignorecase_alwasy"选项设置为全部大小写不敏感。
‘-’ 和 ‘<>’
通常在命令行不识别单个的single-dash‘-’,可以使用如下方法捕获single-dash为参数选项。
GetOptions(
'' => \$single,
) or die $!;
使用GetOptions解析命令行时,当遇到无法识别的字符或者本来不是命令行选项的选项,可以用<>捕获。
## '<>'只能指向函数引用,可以通过函数做很多有意义的事
GetOptions(
'<>' => \&handle,
) or die ;
sub handle
{
my $catch = shift;
print "catch: $catch\n";
}
Getopt::Long::Configure()
指定Getoptions的各项特性
使用方法
## 方式1
use Getopt::Long qw(:config bundling no_ignore_case); ## 参数列表
## 方式2
use Getopt::Long;
Getopt::Long::Configure("bundling", "no_ignore_case"); ## 参数列表
default
bundling(default: disable)
可使用捆绑选项
bundling_override(default: disable)
用长选项重写bundling中出现的短选项。
ignore_case(default: enable)
默认大小写不敏感,对bundling状态的-<single-character>选项无效;
no_ignore_case该选项禁用,同时也会禁用ignore_case_always
ignore_case_always(default: disable)
针对bundling状态的大小写忽略
pass_through (default: disable)
对于GetOptions()中无法识别或者不需要识别或者无效的选项,都不会返回错误。
可以用于多级程序调用时的参数传递。因为GetOptions()会将识别的选项从@ARGV中取出,所以剩余的内容就可以继续传递到下一级程序。
debug(default: disable)
查看Getopt::Long模块处理参数时的debug信息
$#ARGV
表示命令行中参数的个数-1,表示最后一个参数的索引号
最后一个参数:$ARGV[$#ARGV]、或者$ARGV[-1]
$scalar = @ARGV
将命令参数列表赋值给一个标量,该标量表示参数个数
$0 – 表示脚本名称
注意:包括从输入开始到脚本名结束的全部字符,包括path,如~/perl.pl arg0 arg1,$0为~/perl.plss
注意:GetOptions后,@ARGV里面将没有参数了,均已挨个取出分析
return和print区别
print即立马打印内容到终端;
return是将结果作为返回的内容,对于返回的内容处理由其他的命令执行
作为函数返回结果的命令,如
sub subroutine_name {
body of the subroutine
}
&subroutine_name(@_)
传参:@_ 接收
return 返回值
示例
sub NCP_SPLIT_YES_pat_gen_sub_0_new_ncp_strategy{
my $here = << 'PAT_SAVE';
// Begin ATPG_NCP_SPLIT = YES pattern generation
set ext_pat_list ""
foreach current_ncp "$ncp_list" {
puts "+++---current pattern generation for NCP of $current_ncp"
set ext_pat_list "$ext_pat_list $current_ncp "
reset_state
reset_au_faults
// reset_au but not re-build faults list to let pattern gen efficient
//delete_faults -all
//read_faults $env(rpt_dir)/${mode}_before_patgen_faults.txt.gz
set_capture_procedures off -all
set_capture_procedures on $current_ncp
PAT_SAVE
return($here) ;
} #End of NCP_SPLIT_YES_pat_gen_sub_0_new_ncp_strategy
return命令是将内容作为子程序的结果返回
while和foreach读取文件内容
while:读取到空行结束,读取下一行
foreach:读取到空行,将空行作为$_去执行结构体,知道读取到文件结尾结束
perl中常用命令
perl中很多基本语法在前文已总结,对于perl中常用的命令只是零星的给出,此处做较全面的总结。
grep
syntax:
1 grep BLOCK LIST
2 grep EXPR, LIST
BLOCK表示一个code块,通常用{}表示;EXPR表示一个表达式,通常是正则表达式。原文说EXPR可是任何东西,包括一个或多个变量,操作符,文字,函数,或子函数调用。
LIST是要匹配的列表。
grep对列表里的每个元素进行BLOCK或EXPR匹配,它遍历列表,并临时设置元素为$_。在列表上下文里,grep返回匹配命中的所有元素,结果也是个列表。在标量上下文里,grep返回匹配命中的元素个数。
例子1:
将数组的每个元素的空格用_代替
my @arr=("Head PMA1","Head PMA2","Head PMA3","Head PMA4","Head PMA5","Head PMA6");
my @arr1=grep $_=~s/\s/_/g,@arr;
#元素个数
my $arr1_Lenght=@arr1;
print "@arr1:\n$arr1_Lenght";
输出结果
Head_PMA1 Head_PMA2 Head_PMA3 Head_PMA4 Head_PMA5 Head_PMA6:
6
例子2:去除哈希所有键的_
my %IOtypes = ("D_O", 0, "A_O", 1, "D_I", 2, "A_I", 3);
#去除哈希所有键的_
foreach my $Io (grep $_=~s/_//g, keys %IOtypes )
{
print "$Io\t";
}
输出结果
DO AI AO DI
Grep vs. loops
open FILE "<myfile" or die "Can't open myfile: $!";
print grep /terrorism|nuclear/i, <FILE>;;
这里打开一个文件myfile,然后查找包含terrorism或nuclear的行。<FILE>;返回一个列表,它包含了文件的完整内容。
可能你已发现,如果文件很大的话,这种方式很耗费内存,因为文件的所有内容都拷贝到内存里了。
代替的方式是使用loop(循环)来完成:
while ($line = <FILE>;) {
if ($line =~ /terrorism|nuclear/i) { print $line }
}
上述code显示,loop可以完成grep能做的任何事情。那为什么还要用grep呢?答案是grep更具perl风格,而loop是C风格的。
更好的解释是:(1)grep让读者更显然的知道,你在从列表里选择某元素;(2)grep比loop简洁。
符号辨识
!!$var
defined$var
判断变量$var是否有初始化值,my $var;表示没有初始化值。my $var = “”;表示有初始化。
exists $var
用于判断hash、array(ref)中的元素是否存在,function函数是否定义。exists argument is a HASH or ARRAY element,exists操作的对象需要是一个hash或者array元素。
判断一个hash中的键是否存在,键存在但有可能是undef。在hash中,当检验一个元素值是否被定义赋值是用defined,当检验一个key在hash中是否存在时,用exists(即使该键下的值不存在)
print "Exists\n" if exists $hash{$key}; # 这个exists可以避免了键$hash{$key}不存在返回undef造成程序报错的情况
print "Defined\n" if defined $hash{$key};
print "True\n" if $hash{$key};
这里:
$hash{$key}是值,键的获取方式是my $key = keys %hash;
$variable
多维哈希
定义
一维hash的赋值方式多种多样,而多维hash使用最基本的单点赋值方式赋值
my %my_hash;
my $sig1 = "amod_bmod_awsize";
my $sig2 = "bmod_amod_bresp";
$my_hash{$sig1}{name} = "amod_bmod_awsize";
$my_hash{$sig1}{width} = 8;
$my_hash{$sig1}{link}{src} = "amod";
$my_hash{$sig1}{link}{dst} = "bmod";
$my_hash{$sig2}{name} = "bmod_amod_bresp";
$my_hash{$sig2}{width} = 2;
$my_hash{$sig2}{link}{src} = "bmod";
$my_hash{$sig2}{link}{dst} = "amod";
$my_hash{$sig2}{sel}{0} = 0;
$my_hash{$sig2}{sel}{2} = 2;
$my_hash{$sig2}{sel}{10} = 10;
多维hash一样可以跟一维一样用胖箭头赋值
多维hash的某一个key可能指向某一个值,也可能指向一个hash,例如上式中$my_hash{$sig2}指向一个多维hash,$my_hash{$sig2}{name}指向一个值。指向hash的键是一个引用(地址),指向其值(hash)。
注意:而一个key是不能即指向一个值又指向一个其他的东西。
$my_hash{$sig} = "awsize";
$my_hash{$sig}{src} = "a";
$my_hash{$sig}{dst} = "b";
上写法不对,键$my_hash{$sig}的值为“awsize”后就不能再作为键,来指向hash(src=>a,dst=>b)
赋值时,$my_hash{$sig}{dst} = "b" 和 $my_hash{$sig}{"dst"} = "b"是一样的,当然%hash_A = ("key1" => value1, "key2" => value2) 和 %hash_A = (key1 => value1, key2 => value2) 也是一样的,keyx会自动被引号引起来。
打印
一维hash一般直接print %hash就够用了,而对于嵌套的多维数组呢,可以借助一个库来实现清晰的打印:
use Data::Dumper;
my %my_hash;
........
print Dumper(\%my_hash);
%my_hash:
$VAR1 = {
'bmod_amod_bresp' => {
'name' => 'bmod_amod_bresp',
'width' => 2,
'sel' => {
'10' => 10,
'2' => 2,
'0' => 0
},
'link' => {
'dst' => 'amod',
'src' => 'bmod'
}
},
'amod_bmod_awsize' => {
'link' => {
'dst' => 'bmod',
'src' => 'amod'
},
'width' => 8,
'name' => 'amod_bmod_awsize'
}
};
上打印的格式是默认格式,可以使用下脚本对打印经行控制
#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
sub display_hash{
my $obj = shift @_;
my $tab_n = shift @_;
my $tab = "";
my @re;
$tab_n = 0 unless $tab_n;
$tab = " " x $tab_n;
my %hash = %$obj;
for my $key(sort {$a cmp $b} keys %hash){
$str = $tab."$key";
if(ref $hash{$key} eq "HASH"){
#$str .= "\n";
push(@re, $str);
@re = (@re, &display_hash(\%{$hash{$key}}, $tab_n+4));
} else {
$str .= " => $hash{$key}";
push(@re, $str);
}
}
return @re;
}
sub display_list{
my @list = @_;
for my $obj (@list){
print "$obj\n";
}
}
&display_list(&display_hash(\%my_hash)); # 从右往左计算的优先级
执行的结果:
amod_bmod_awsize
link
dst => bmod
src => amod
name => amod_bmod_awsize
width => 8
bmod_amod_bresp
link
dst => amod
src => bmod
name => bmod_amod_bresp
sel
0 => 0
10 => 10
2 => 2
width => 2
删除
同一维hash一样,删除一个key会将其所指向的内容全部删除:
delete $my_hash{bmod_amod_bresp}{width};
delete $my_hash{"amod_bmod_awsize"}{name};
遍历
下层hash用%{}转一下:
for my $obj0 (sort keys %my_hash){
for my $obj1(sort keys %{$my_hash{$obj0}}){
print "$obj1, $my_hash{$obj0}{$obj1} \n";
}
}
结果:
link, HASH(0x190a4e0)
name, amod_bmod_awsize
width, 8
link, HASH(0x19793f8)
name, bmod_amod_bresp
sel, HASH(0x19439b8)
width, 2
引用
正常的$obj = \%my_hash引用就可以了,解引用也可直接%hash = %$obj,或者不解直接用$obj->{$sig1}->{name}这样用应该也是没问题的,以下三种方式都可以:
my $hash = \%my_hash;
print "hello1, $hash->{amod_bmod_awsize}->{name} \n";
print "hello2, $hash->{amod_bmod_awsize}{name} \n";
print "hello3, ${$hash}{amod_bmod_awsize}{name} \n";
结果:
hello1, amod_bmod_awsize
hello2, amod_bmod_awsize
hello3, amod_bmod_awsize
拷贝
hash进行=直接拷贝的话,是一种深层指针拷贝,看下这个代码:
delete $my_hash{$sig1}; # no use, to long
my $sig3 = "bmod_amod_buser";
$my_hash{$sig3} = $my_hash{$sig2};
print "first, copy=====================\n";
&display_list(&display_hash(\%my_hash));
print "\nfirst, delete====================\n";
delete $my_hash{bmod_amod_bresp}{width};
&display_list(&display_hash(\%my_hash));
结果:
first, copy=====================
bmod_amod_bresp
link
dst => amod
src => bmod
name => bmod_amod_bresp
sel
0 => 0
10 => 10
2 => 2
width => 2
bmod_amod_buser
link
dst => amod
src => bmod
name => bmod_amod_bresp
sel
0 => 0
10 => 10
2 => 2
width => 2
first, delete====================
bmod_amod_bresp
link
dst => amod
src => bmod
name => bmod_amod_bresp
sel
0 => 0
10 => 10
2 => 2
bmod_amod_buser
link
dst => amod
src => bmod
name => bmod_amod_bresp
sel
0 => 0
10 => 10
2 => 2
可以发现,拷贝是吧全部信息都拷过去了,但是$sig2 width被删除时,$sig3中对应的信息也被删除了。因此需要深度复制拷贝的话,请使用:
use Clone 'clone';
ref函数
perl有引用的概念:一组数据实际上是另一组数据的引用。这些引用称为指针,第一组数据中存放的是第二组数据的头地址。引用的方式被用得相当普遍,特别是在面向对象的模块、函数的参数传递等常见。但perl对每个引用都是以一个普通的变量来定义的,有时候,如果数据的架构比较复杂,我们可能会困惑于某个变量所指向的地址的实际内容是什么?perl的ref函数就可以帮助我们。
说明
从perl自带的帮助说明可以了解相关的用法:
引用
$ perldoc -tf ref
ref EXPR
ref Returns a non-empty string if EXPR is a reference, the empty
string otherwise. If EXPR is not specified, $_ will be used. The
value returned depends on the type of thing the reference is a
reference to. Builtin types include:
SCALAR
ARRAY
HASH
CODE
REF
GLOB
LVALUE
If the referenced object has been blessed into a package, then
that package name is returned instead. You can think of "ref" as
a "typeof" operator.
if (ref($r) eq "HASH") {
print "r is a reference to a hash./n";
}
unless (ref($r)) {
print "r is not a reference at all./n";
}
举例
简单来说,就是如果一个变量是个引用,那ref就可以返回一个表示其实际引用对象的描述性字符串,否则就会返回空值。如果没有指定ref函数的参数,默认对$_变量操作。如果被引用的对象已经被打包,则会返回该包的名称,类似typeof操作符。
代码:
#!/usr/bin/perl -w
%hash=('Tom'=>'Male','Jerry'=>'Female');
$href=\%hash;
for my $key (keys %$href) {
print $key." => ".$href->{$key};
print "\n";
}
if ( ref($href) eq "HASH" ) {
print "href is a reference to a hash./n";
}
unless ( ref($href) ) {
print "href is not a reference at all./n";
}
print "href is ",ref($href),"./n";
输出结果:
执行
$ perl testref.pl
结果:
Jerry => Female
Tom => Male
href is a reference to a hash.
href is HASH.
示例:(%my_hash已初始化)
my %my_hash;
my $sig1 = "amod_bmod_awsize";
my $sig2 = "bmod_amod_bresp";
$my_hash{$sig1}{name} = "amod_bmod_awsize";
$my_hash{$sig1}{width} = 8;
$my_hash{$sig1}{link}{src} = "amod";
$my_hash{$sig1}{link}{dst} = "bmod";
$my_hash{$sig2}{name} = "bmod_amod_bresp";
$my_hash{$sig2}{width} = 2;
$my_hash{$sig2}{link}{src} = "bmod";
$my_hash{$sig2}{link}{dst} = "amod";
$my_hash{$sig2}{sel}{0} = 0;
$my_hash{$sig2}{sel}{2} = 2;
$my_hash{$sig2}{sel}{10} = 10;
1 print "ref function returns 'HASH if EXPR is hash'\n"if (ref %my_hash); # ref %hash返回值为空,即没有返回值
2 print "ref %my_hash:",ref %my_hash,"\n"; # 同上,为空
3 print "ref \\%my_hash:",\%my_hash,ref \%my_hash,"\n"; # ref \%my_hash 返回值HASH,即\%my_hash表示引用地址
4 print "$my_hash{$sig1}:",ref $my_hash{$sig1},"\n"; # $my_hash{$sig1}是引用,也是哈希my_hash的键,值为另一个哈希
5 print "$my_hash{$sig1}{link}:",ref $my_hash{$sig1}{link},"\n"; # $my_hash{$sig1}{link}为引用,指向一个哈希,本身是键
6 print "$my_hash{$sig1}{name}:",ref $my_hash{$sig1}{name},"\n";
解果:
1 NULL
2 ref %my_hash:
3 ref \%my_hash:HASH(0x23162f0)HASH
4 HASH(0x2187d48):HASH
5 HASH(0x23769e8):HASH
6 amod_bmod_awsize:
函数
函数的声明与定义
Perl函数声明的语法为:
sub NAME [PROTOTYPE] [ATTRIBUTE]
Perl函数定义的语法为:
sub [NAME] [PROTOTYPE] [ATTRIBUTE] BLOCK
sub(函数关键字):Perl中的子函数关键字,不可省略。
NAME(函数名字):函数名字在函数声明中是必需的,而在函数定义中则是可选的。在函数定义中如果省略函数名则表示声明了一个匿名函数,此时需要提供一个调用匿名函数的方式
PROTOTYPE(函数原型):用来定义函数出入参数的格式
ATTRIBUTE(函数属性):用来定义函数的属性
BLOCK(函数体):函数的代码体,只存在函数的定义中
函数的调用方式
Perl中函数的调用方式主要有三种:
通过函数名直接调用
这种调用方法只能调用命名函数。它的调用语法为:
NAME[(param1,param2,…)]
如果函数调用之前已经做了函数的声明或者定义,那么函数名字后面的括号是可以省略的。如果函数在调用之前没有做函数的声明或者定义,后面的括号不可省略。
使用前置&号调用
这种调用方式也只能调用命名函数。它的调用语法为:
&NAME[(pamram1,param2,…)]
这种调用方式下,不论声明或者定义是否在函数调用之前,函数名后面的括号均可以省略,因为符号&明确告诉Perl解释器这是一个函数调用,Perl解释器会在所有可见的名字空间中寻找该函数,如果找不到会报运行时错误。
使用引用调用
这种调用方式既可以调用命名函数也可以调用匿名函数。调用匿名函数时需要用一个标量变量来保存对匿名函数的引用。这种方式的调用语法有以下两种:
&$subref[()]
$subref->()
&$subref
引用调用还可以调用匿名函数,但首先要保存一个匿名函数的引用。保存匿名函数的引用的语法如下:
$subref=sub BLOCK;
保存了匿名函数的引用之后,调用方式同上面命名函数的引用调用方式相同。
文件、目录类型判断
文件属性判断操作符通常与if 配合使用
文件相关
测试操作符 含义
-r 当前用户对此文件是否拥有可读权限
-w 当前用户对此文件是否拥有可写权限
-x 当前用户对此文件是否拥有可执行权限
-o 此文件所有者是否是当前用户
-f 文件是否是普通文件
-d 文件是否是目录文件
-l 文件是否是链接文件
-e 文件或目录存在
-z 判断文件内容为空,不能用于判断目录
-s 判断文件或目录存在, 返回文件或目录的大小, 单位为字节
逻辑表达式组合
- perl 可以使用and 和 or 表示逻辑与和逻辑或的关系
- 隐式文件句柄 _ 表示上次监测的文件, 用于提升效率
if ( -f $file and -x _ ) {
print "文件$file 存在且可执行\n";
}
文件读写操作
文件
1.1open-close
open FILEHANDLE, EXPR
...
open(FILE,"<sim.log") or die "can't open sim.log,$!";
#open(FILE,"<","sim.log") or die "can't open sim.log,$!"; #也可以
#open(FILE,"r","sim.log"); #不支持
while(<FILE>){ #<>为钻石操作符,按行读取文件内容
print "$_\n";
}
close FILE;
#close; #也可以,但不建议,容易出错
EXPR中:
< 只读(open默认方式),文件指针指向开头;不存在则报错
> 只写,文件指针指向开头;不存在则尝试创建
>> 只写,文件指针指向结尾(追加);不存在则尝试创建
+< 读写,文件指针指向开头,写多少覆盖不少;不存在则报错
+> 读写,文件大小直接截为0;不存在则尝试创建
+>> 读写,文件指针指向结尾;不存在则尝试创建
1.2读写文件
<> 文件句柄操作符,<FILEHANDLE>读取句柄指向的文件的内容,标量环境返回一行内容,数组环境返回整个文件内容。<>默认从命令行参数列表@ARGV中的文件中读取内容,@ARGV中若无元素,则从STDIN标准输入文件句柄中读取,也可使用<FILEHANDLE>手动指定句柄。
*rename string1,string2;重命名
*unlink filename1;删除文件
1.3文件位置
tell FILEHANDLE:获取文件当前位置,以字节计;
seek FILEHANDLE, POSITION, WHENCE:移动读写指针,position指定移动的字节数,whence指定移动的起点,0,1,2分别表示文件开头、当前位置,结尾。
sysopen(DATA,"sim3.log",O_RDONLY) or die "can't open sim.log,$!";
#following sysopen doesn't work 只读的模式下可以添加0755么?
#sysopen(DATA2,"./sim2.log",O_WRONLY|O_CREAT,0755) or die "can't create sim2.log,$!";
open DATA2,"+>sim2.log" or die "can't open sim2.log,$!";
while(<DATA>){
print DATA2 $_;#there is no "," between DATA2 and $_
printf "DATA2 position:%d\n",tell DATA2;
#finally,print moves ptr of DATA2 to the end
}
print tell DATA2,"\n";
seek DATA2,0,0; #重定向读写指针到文件开头,否则下面的while无法执行
print tell DATA2,"\n";
while(<DATA2>){
print "in sim2.log: $_\n";
}
1.4文件信息
-A 文件上一次被访问的时间(单位:天)
-B 是否为二进制文件
-M 文件上一次被修改的时间(单位:天)
-T 是否为文本文件
-d 为目录
-e 文件或目录名存在
-f 为普通文件
-l 为符号链接
-p 文件是命名管道(FIFO)
-s 文件或目录存在且不为0(返回字节数)
-z 文件存在,大小为0(目录恒为false),即是否为空文件,
md5加密算法
md5算法,全称是Message-Digest Algorithm 5,即信息摘要算法。
MD5是一种哈希算法,可以将任意长度的数据转换为固定长度的哈希值,通常用于验证数据完整性,即通过比对两个数据的MD5值来判断它们是否相同。文件是计算机中的一种数据存储形式,可以保存数据或程序。文件也可以通过MD5算法计算出其哈希值, MD5是一种数字指纹,而文件则是一个具体的数据或程序,md5除了应用于文件内容校验,还包括密码加密等应用场景。
例如:
在使用已知的10个文件作为源文件用来生成输出文件,为了防止在输出文件生成之后,源文件遭到修改或者破坏,可以使用md5算法得到源文件的哈希值。
md5算法有以下特点:
压缩性:任意长度的数据,算出的MD5值长度都是固定的。
容易计算:从原数据计算出MD5值很容易。
抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
示例:
use Digest::MD5 qw(md5_hex)
system “md5sum $file”;
结果:
473c42befc033ec760f6dc7181866d81 edt_saf_single_clk_func_addsmsgcxfinaltunecom/rpt/md5sum.rpt
==念念不忘,会有回响==
END