Perl学习笔记(3)——控制结构/文件/排序/进程管理

Perl学习笔记(3)

  • 一、控制结构
    • 1.1 unless结构
    • 1.2 until结构
    • 1.3 elsif
    • 1.4 ++/-\-
    • 1.5 循环控制
    • 1.6 " ? :" 操作符
    • 1.7 逻辑操作符 :&& 、||
  • 二、文件测试及目标操作
    • 2.1 文件测试
      • 2.1.1 文件测试操作符
      • 2.1.2 stat和lstat函数
    • 2.2 目标操作
      • 2.2.1 在目录树中移动
      • 2.2.2 文件名通配
      • 2.2.3 目录句柄
    • 2.2.4 删除文件
      • 2.2.5 重命名文件
    • 2.2.6 建立及删除目录
    • 2.2.7 修改权限
    • 2.2.8 修改隶属关系
    • 2.2.9 修改时间戳
  • 三、字符串与排序
    • 3.1 在字符串内用index搜索
    • 3.2 用substr处理子串
    • 3.3 用sprintf格式化输出
    • 3.4 高级排序
  • 四、进程管理
    • 4.1 system函数
    • 4.2 exec函数
    • 4.3 环境变量
    • 4.4 使用反引号捕获输出结果
    • 4.5 使用fork进行并发操作

一、控制结构

1.1 unless结构

当条件为假时,执行指定的语句:

my $fred = "45";
unless ($fred =~ /^[A-Z_]\w*$/i) {
	print "\n[1]The value of \$fred doesn't look like a Perl identifier name.\n\n";
}

my $mon = "Feb";
unless ($mon =~ /^Feb/) {
	print "[2]This month has at least thirty days.\n\n";
}
else {
	print "[2]Do you see what's going on here?\n\n";
}

my $mon = "Mar";
unless ($mon =~ /^Feb/) {
	print "[3]This month has at least thirty days.\n\n";
}
else {
	print "[3]Do you see what's going on here?\n\n";
}

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第1张图片

1.2 until结构

循环体一直执行,直到条件为真:

my $j = 1;
my $i = 20;
print "\n";
until ($j > $i) {
	$j *= 2;
	print "j = $j \n\n"
}

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第2张图片

1.3 elsif

类似于verilog中的 else if
sim.log:



Compile rtl...

./simv update

# -----------------------------------------
# teststatus: failed
# failed_reason: check failed for y output
# -----------------------------------------
my $file = "sim.log";
print "\n";
open (LOG,"<",$file) or die "can not open $file for reading!\n";
while (defined (my $line = )) {
	if ($line =~ /^\s*$/) {
		print "it is a empty line!\n\n";
	}
	elsif ($line =~ /compile\s+rtl/i) {
		print "start to compile rtl.\n\n";
	}
	elsif ($line =~ /teststatus:\s*(\w+)/) {
		print "detectd the test status and status is \"$1\"\n\n";
	}
	elsif ($line =~ /failed_reason:\s*(.*)/) {
		print "detectd the failed reason and the reasons is \"$1\"\n\n";
	}
}
close (LOG);

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第3张图片

1.4 ++/--

$i- - 先赋值后自减
$i++
- -$i
++$i

print "\n";
my $n = 0;
for (my $i = 0;$i <3 ; $i ++) {
	print "i = $i ;\n";
}
print "-"x30 . "\n";

my $m = 5;
my $a = ++$m;	#m=6
my $b = --$m;	#m=5
my $c = $m++;	#m=6 , c=5
my $d = $m--;	#m=5 , c=6
print "a = $a ,b = $b ,c = $c,d = $d,m = $m;\n";

在这里插入图片描述

1.5 循环控制

循环控制用于佛for、foreach、while、until等循环;

  • last
    用于立刻终止当前循环,类似c中的break
  • next
    结束当前这次循环的迭代,类似c中的continue
  • redo
    控制返回到本次循环的顶端(开始next和redo者的最大区别在于next会正常继续下一次迭代,而redo则会重新执行这次的迭代。
  • 带标签的块
    将标签和一个冒号放在循环前而来创建带标签的循
    环块;可使用标签从内层对外层循环块进行控制;last,next,redo后面可以接标签名。
my $file = "info.log";
open (LOG,"<",$file) or die "Can not open $file for reading!\n";
my $line_num = 0;
while (defined (my $line = )) {
	$line_num++;
	print "line_num = $line_num \n";
	next if ($line =~ /^phone/i);
	last if ($line =~ /^version/i);
	print "current line = $line \n\n";
}
close (LOG);

print "="x40 . "\n";
for (my $i = 0; $i < 2 ; $i++) {
	print "\ni = $i \n";
	for (2..4) {
		last if ($_ == 3);
		print "i = $i ,j = $_ \n";
	}
}

print "="x40 . "\n";
FOR_LOOP: for (my $i = 0; $i < 2 ; $i++) {
	print "\ni = $i \n";
	for (2..4) {
		last FOR_LOOP if ($_ == 3);
		print "i = $i ,j = $_ \n";
	}
}

在phone那行没显示跳出本次循环,在version那行没显示,直接结束循环。
Perl学习笔记(3)——控制结构/文件/排序/进程管理_第4张图片
后一次last if 指定循环FOR_LOOP直接跳出,前一次则跳出所在循环。
Perl学习笔记(3)——控制结构/文件/排序/进程管理_第5张图片

1.6 " ? :" 操作符

  • 语法:
expression ? if_ture_expr : if_false_expr

1.7 逻辑操作符 :&& 、||

for (1 .. 6) {
	my $num = $_;
	if ($num < 4 && $num >1) {
		print "num = $num and this is the \"&&\"\n\n";
	}
	elsif ($num == 4 || $num == 6) {
		print "num = $num and this is the \"||\"\n\n";
	}
}

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第6张图片

二、文件测试及目标操作

2.1 文件测试

2.1.1 文件测试操作符

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第7张图片
Perl学习笔记(3)——控制结构/文件/排序/进程管理_第8张图片

my @files = qw(ext5.0.pl ext5.1.pl ext5.2.pl ext5.3.pl ext5.4.pl ext5.5.pl ext5.6.pl ext5.7.pl);
my @small_files;
print "\n";
foreach my $file (@files) {
	if (! -e $file) {
		print "$file does not exist in current dir \n\n";
	}
	elsif (-s $file < 100_000) {
		push (@small_files, $file)
	}
}
if (defined $small_files[0]) {
	my $num = @small_files;
	print "\nThe following $num files' size are samller than 100KB:\n";
	print "-"x40 . "\n";
	print "@small_files";
}

在这里插入图片描述
Perl学习笔记(3)——控制结构/文件/排序/进程管理_第9张图片

2.1.2 stat和lstat函数

  • stat
    返回和同名linux系统调用类似的文件信息(访问属性,用户编号及组ID,文件或目录的链接数,时间戳)
    函数的参数可以是文件句柄或文件名。stat函数正常情况下会返回一个含有13个数字元素的列表,执行失败时返回空列表
  • Istat
    和stat函数类似,但它的参数必须是符号链接
  • localtime
    获得当前时间,和date效果一致
  • gmtime
    获得标准格林威治时间(英国标准时间,和北京时间相差人概8小时)
  • Time
    返回值为一个整数,表示从XX年开始到现在时间的总秒数
my $local_time 	= localtime();
my $time	= time();
my $gm_time	= gmtime();
print "local_time = $local_time\n";
print "time = $time\n";
print "gm_time = $gm_time\n";

my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdat) = localtime();
print "\nsec = $sec\n";
print "min = $min\n";
print "hour = $hour\n";
print "day = $day\n";
print "mon = $mon\n";
print "year = $year\n";
print "wday = $wday\n";
print "yday = $yday\n";
print "isdat = $isdat\n";

$year +=1900;
$mon += 1;
my $btime = sprintf ("%d/%02d/%02d/%02d:%02d:%02d",$year,$mon,$day,$hour,$min,$sec);
print "\nyear = $year \n";
print "mon = $mon\n";
print "btime = $btime\n";

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第10张图片

2.2 目标操作

2.2.1 在目录树中移动

  • chdir:该函数用于改变当前的工作目录
    。由Perl程序启动的所有进程,都会继承Perl程序的工作目录
    。对于启动Perl程序的进程,它的工作目录不会随Perl程序的工作目录的改变而改变
    。chdir省略参数时,会回到用户的主目录
    。一旦退出Perl程序,会回到开始的工作目录

2.2.2 文件名通配

  • glob
    能够在命令行上键入的模式,都可以作为glob的参数。如果需要一次匹配多种模式,可以在参数中用空格隔开各个模式。
my @all_files = golb"*";	#不含以点开始的文件
my @pm_files = glob "*.pm";
my @all_files_including_dot=glob ".**";
  • < >
my $dir = "/etc"
my @dirfiles = <$dir/* $dir/.* >;

2.2.3 目录句柄

  • opendir
    打开文件句柄
  • readdir
    读取目录句柄的内容(读到的是目录里的文件名)
  • closedir
    关闭目录句柄
my $dir = "./";
opendir DIR,$dir or die "Can not open $dir: $!";
print "\n";
foreach my $file (readdir DIR) {
	if ($file eq ".") {
		print "[WARN] -- current obtained file in $dir dir starts with \".\" and skip it \n";
	}
	elsif ($file eq "..") {
		print "[WARN] -- current obtained file in $dir dir starts with \"..\" and skip it \n";
	}
	else {
		print "[INFO] -- current obtained file in $dir dir is $file \n";
	}
}
closedir DIR

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第11张图片

2.2.4 删除文件

  • unlink
    unlink用于删除文件(而不能用来删除目录),它的返回值代表成功地删除了多少个文件
unlink "slate","bedrock","lava";
unlink glob "*.o";

2.2.5 重命名文件

  • rename
    重命名文件失败返回假
foreach my $file (glob "./logs/*.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) {
		print "rename $file to $newfile successfully!\n";
	}
	else {
		print "rename $file to $newfile failed: &!\n";
	}
}

在这里插入图片描述

2.2.6 建立及删除目录

  • 新建目录
    mkdir dir_name,permission
    用oct函数把字符串表示的权限值转成八进制数字
mkdir sims,0755#0755是八进制数
  • 删除目录
    rmdir dir_name;
    。每次只能删除一个目录
    。对非空的目录调用rmdir操作符会执行失败
    。如何删除非空目录
unlink glob "$tmp_dir/* $tmp_dir/.*";
rmdir $tmpdir;

2.2.7 修改权限

  • chmod
chmod 0755 FileA,FileB;

2.2.8 修改隶属关系

  • chown
    chown操作符会同时更改拥有者和所属组,必须以数字形式的用户标识符和组标识符来指定。getpwnam和getgrnam函数可以分别将用户名和组名翻译成数字。
my $user = 1004;
my $group =100;
chown $user,$group,glob "*.o";

defined (my $user = getpwnam "merlyn") or die "bad user";
defined (my $group = getpwnam "users") or die "bad groups";
chown $user,$group,glob "/home/merlyn/*";

2.2.9 修改时间戳

  • utime
    utime函数用于修改文件的访问时间和修改时间
    utime access_time,modified_time,filelist;
my $now = time,
utime $now,$now,glob"*";

三、字符串与排序

3.1 在字符串内用index搜索

  • index语法
    index函数从$big字符串里寻找$small字符串首次出现的地方,返回一个整数代表第一个匹配字符的位置(从零开始)。如果没有找到子串,则返回-1
$where = index($big,$small);

or

$where = index($big,$small,$start_point);
  • rindex搜索子串最后出现的位置
    rindex可选的第三个参数用来限定返回的最大位置
my $stuff = "Howdy world!";
my $where = index ($stuff,"wor");
print "\n[INFO1] input string = \"$stuff\",where = $where \n\n";

my $where1 = index($stuff,"w"); 		#2
my $where2 = index($stuff,"w",$where1 + 1); 	#6
my $where3 = index($stuff,"w",$where2 + 1); 	#-1
print "\n[INFO2] input string = \"$stuff\",where1 = $where1, where2 = $where2, where3 = $where3 \n\n";

my $fred = "Yabba dabba doo!";
my $where1 = rindex($stuff,"abba"); 		#7
my $where2 = rindex($stuff,"abba",$where1 - 1); #1
my $where3 = rindex($stuff,"abba",$where2 - 1); #-1
print "\n[INFO3] input string = \"$stuff\",where1 = $where1, where2 = $where2, where3 = $where3 \n\n";

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第12张图片

3.2 用substr处理子串

  • 语法规则
    substr操作符用于从一个长字符串中返回一个子串。$part=substr($string,$initial_position,$length);
    当不指定第三个参数时,会一直取到字符串结尾。
  • 起始位置可以为负值,表示从字符串结尾开始倒数
    位置-1是最后一个字符,位置-3是从字符串结尾算起的第3个字符
  • substr可以结合index—起使用
my $mineral = substr("Fred J. Flintstone",8,5);		#gets "Flint"
my $rock = substr("Fred J. Flintstone",13,100);		#gets "stone"
print "\n[INFO_1] mineral = \"$mineral\",rock = \"$rock\"\n\n";

my $pebble = substr("Fred J. Flintstone",13);		#gets "stone"
my $out = substr("some very long string",-3,2);		#gets "in"
print "[INFO_2] pebble = \"$pebble\",out = \"$out\"\n\n";

my $long = "some very very long string";		
my $right = substr($long,index($long,"l"));	#index 15
print "[INFO_3] long = \"$long\",right = \"$right\"\n\n";

my $string = "Hello world!";
substr($string,0,5) = "Goodbye";
print "[INFO_4] string = \"$string\"\n\n";

substr($string,0,7) =~ s/goodbye/ByeBye/ig;
print "[INFO_5] string = \"$string\"\n\n";

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第13张图片

3.3 用sprintf格式化输出

  • sprintf函数可以数据进行格式化,并返回处理过的字符串
my $year = "2020";
my $mon	= "08";
my $day = "02";
my $hour = "19";
my $min = "32";
my $sec = "17";
my $date_tag = sprintf("%4d/%02d/%02d %2d:%02d:%02d",$year,$mon,$day,$hour,$min,$sec);
print "\n[INFO] date_tag = $date_tag \n\n";
# [INFO] date_tag = 2020/08/02 19:32:17

3.4 高级排序

  • sort操作符以ASCII码序对列表进行排序
  • Perl允许建立自己的排序规则了程序实现想要的排序方式
  • 排序最终一定都是两两相比,因此排序子程序只要能比较两个元素就行
  • 要使用排序子程序,只要把它的名字写在sort操作符和待排序的列表之间
    my @result = sort by_number @items;
sub by_number {
	if ($a < $b) {-1} elsif ($a > $b) {1} else {0};
}
  • 三路数字比较操作符<=>
    <=>操作符会比较两个数字并且返回-1,0或者1,好让它们与数字排序
    。数值递增排序
    sub by_number { $a <=> $b }
    。数值递减排序
    sub by_number { $b <=> $a }
    。排序子程序中用到的变量$a和$b并不是数据项的拷贝,它们实际上是原始列表元素的临时化名,如果改变它们的话,会弄乱原始的数据
  • 三路字符串比较操作符cmp
    cmp操作符与sort的默认排序方法相同
    my @strings = sort { $a cmp $b} @any—strings;
my @data_arrays = qw(4 2 10 23 7 40 30 20);
my @rise_arrays = sort {$a <=> $b} @data_arrays;
my @fall_arrays = sort {$b <=> $a} @data_arrays;
print "\n[INFO_0] data_arrays = @data_arrays\n";
print "[INFO_0] rise_arrays = @rise_arrays\n";
print "[INFO_0] fall_arrays = @fall_arrays\n";

my @str_arrays = qw(an good buy eggs cups);
my @rise_arrays = sort {$a cmp $b} @str_arrays;
my @fall_arrays = sort {$b cmp $a} @str_arrays;
print "\n[INFO_1] str_arrays = @str_arrays\n";
print "[INFO_1] rise_arrays = @rise_arrays\n";
print "[INFO_1] fall_arrays = @fall_arrays\n";

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第14张图片

四、进程管理

4.1 system函数

  • system函数是启动Perl子进程最简单的方法
    e.g.:system "date"
    上述例子会创建一个子进程来运行date命令,并且它继承了Perl的标准输入输出。
    e.g.:system 'ls -l $HOME';#单引号防止变量内插
  • 可以利用shell功能来启动后台进程
    e.g.:system "run_cmd with parameters &";
  • system执行正常返回值为0,否则返回值为非0
    !system "rm -r files" or die "operation wrong"
  • system支持多个参数
    第一个参数’‘tar’'是命令名称,后面的参数会被逐项的传递给前面的命令,即使参数里出现对shell有意义的字符(如星号*,管道符号,大小于号以及与号)都不会被shell误解为特殊含义。
my $tarfile = "something*wicked.tar"
my @dirs = qw(fred|flint  bet):
system "tar","cvf",$tarfile,@dirs;#三个待打包目录

如果不采用多参数形式,而采用如下的形式,shell会扩展目录名称@dirs中的特殊字符,造成意想不到的结果:

system "tar cvf $tarfile @dirs";

4.2 exec函数

效果同system类似,用于执行外部命令。system会创建子进程执行外部命令,父进程等待创建的子进程结束并继续执行下而的代码。exec不会开启子进程,而是取代父进程,因此执行完引号中的命令后进程即结束。一般和fork配合使用。

exec调用之后写的任何代码都无法运行

  • 如果确定不了到底要用system还是exec,就用system,大多数情况下都是稳妥的

Example:

chdir "/tmp" or die "Cannot chdir/tmp:$!";
exec "bedrock","-o","args1",@ARGV;

4.3 环境变量

  • 环境变量对应于特殊的%ENV哈希,每个键代表一个环境变量
  • 程序开始运行时,%ENV会保留从父进程(通常为shell)继承来的设定值
  • 修改%ENV就能改变环境变量,并能被Perl调用的子进程继承
$ENV{'PATH'} = "/home/usra/bin:$ENV{'PATH'}";
  • 修改从父进程继承的变量并不影响sh刨或其他父进程

4.4 使用反引号捕获输出结果

  • system和exec调用外部程序的输出会定向到标准输出
  • 使用反引号调用外部命令可以捕获被调用程序的输出
my $now = `date`;
  • 使用反引号时反斜线转义和变量内插都会正常处理
  • 使用反引号调用命令时按行返回且每行结束带一个回车

4.5 使用fork进行并发操作

fork用于从一个进程中创建两个进程。如果它成功,该函数给父进程返回新创建的子进程ID,而给子进程返回0。如果系统没有足够的资源分配一个新的进程,那么调用失败并返回undefo

父进程可以使用waitpid函数等待子进程的结束。

my $opt = 0;
my $localtime;
if (@ARGV > 0) {
	$opt = $ARGV[0];
}
else {
	print "Usage: perl $0 opt \n";
	print "		Where opt = 0 or 1 \n";
	exit;
}

if ($opt == 1) {
	defined (my $pid = fork()) or die "Fork process failured:$!\n";
	unless ($pid) {
		print "\n[DEBUG1] This is the child process.\n\n";
		$localtime = localtime();
		print "[DEBUG1] -- child:current time is $localtime \n\n";
		sleep(3);
		print "[DEBUG1] Exit child after 3seconds wait!\n";
		exit();
	}
	print "[DEBUG1] This is the parent process.\n\n";
	waitpid($pid,0);
	$localtime = localtime();
	print "[DEBUG1] -- parent:current time is $localtime \n\n";
	print "[DEBUG1] exit parent!\n\n";
}
else {
	defined (my $pid1 = fork()) or die "Fork process failured:$!\n";
	unless ($pid1) {
		print "\n[DEBUG2] This is the child process.\n\n";
		$localtime = localtime();
		print "[DEBUG2] -- child:current time is $localtime \n\n";
		sleep(3);
		print "[DEBUG2] Exit child after 3seconds wait!\n";
		exit();
	}
	print "[DEBUG2] This is the parent process.\n\n";
	$localtime = localtime();
	print "[DEBUG2] -- parent:current time is $localtime \n\n";
	print ("[DEBUG2] exit parent!\n\n");
}

Perl学习笔记(3)——控制结构/文件/排序/进程管理_第15张图片

你可能感兴趣的:(脚本语言,Perl)