加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Perl笔记5

发布时间:2020-12-16 00:05:15 所属栏目:大数据 来源:网络整理
导读:第十三章:目录操作 (1) 在目录树中移动 使用chdir操作符来改变当前的工作目录 chdir '/etc' or die "cannot chdir to /etc: $!"; (2) 文件名通配 foreach $arg (@ARGV) { ? ? print "one arg is $argn"; } perl show-args *.pm one arg is barney.pm one a
第十三章:目录操作 (1) 在目录树中移动 使用chdir操作符来改变当前的工作目录 chdir '/etc' or die "cannot chdir to /etc: $!"; (2) 文件名通配 foreach $arg (@ARGV) { ? ? print "one arg is $argn"; } perl show-args *.pm one arg is barney.pm one arg is dino.pm ...... 程序内部可以使用glob操作符来实现通配功能: chdir 'D:PerlModuleDateTime-1.03' or die "Cannot chdir to D: $!"; my @all_files = glob '*.yml'; #列出所有以.yml结尾的文件名 print "@all_filesn"; my @all_files = glob '.* *'; #如果要一次匹配多种模式,可以在参数中用空格隔开各个模式 .*表示.和.. ?*匹配所有的文件 print "@all_filesn"; (3) 文件名通配的另一种语法 在glob出现之前,使用<>来调用此功能: my @all_files = <.*>; my $dir = '/etc'; my @dir_files = <$dir/* $dir/.*>; (4) 目录句柄 若想从目录里取得文件名列表,还可以使用目录句柄 opendir readdir closedir my $dir_to_process = 'D:PerlModuleDateTime-1.03'; opendir my $dh,$dir_to_process or die "Cannot open $dir_to_process: $!"; foreach $file (readdir $dh) #readdir返回的是文件名,不包括路径名 { ? ? print "one file in $dir_to_process is $filen"; } close $dh; #会列出D:PerlModuleDateTime-1.03目录下面所有的文件 one file in D:PerlModuleDateTime-1.03 is . one file in D:PerlModuleDateTime-1.03 is .. one file in D:PerlModuleDateTime-1.03 is Build one file in D:PerlModuleDateTime-1.03 is Build.bat one file in D:PerlModuleDateTime-1.03 is Build.PL ...... one file in D:PerlModuleDateTime-1.03 is README one file in D:PerlModuleDateTime-1.03 is t one file in D:PerlModuleDateTime-1.03 is TODO one file in D:PerlModuleDateTime-1.03 is tools one file in D:PerlModuleDateTime-1.03 is _build 也可以使用裸字作为目录句柄的名称: my $dir_to_process = 'D:PerlModuleDateTime-1.03'; opendir DIR,$dir_to_process or die "Cannot open $dir_to_process: $!"; foreach $file (readdir DIR) #readdir返回的是文件名,不包括路径名 { ? ? print "one file in $dir_to_process is $filen"; } close DIR; #为了让程序更具可移植性,可以使用File::Spec::Functions模块构造适合本地系统文件名 use File::Spec::Functions; $dirname = 'D:PerlModuleDateTime-1.03'; opendir my $somedir,$dirname or die "Cannot open $dirname: $!"; while (my $name = readdir $somedir) { ? ? next if $name =~ /^./; ? ? $name = catfile($dirname,$name); ? ? next unless -f $name and -r $name; ? ?? ? ? print "$namen"; } (5) 递归访问目录 Perl自带了一个模块File::Find,可以实现目录的递归处理。 (6) 目录和文件的操作 1. 在Perl里面,我们可以使用unlink操作符,并指定要删除的文件列表 unlink 'slate','bedrock','lava'; unlink qw(slate bedrock lava); unlink glob '*.o'; #glob '*.o'返回的是一个列表 unlink的参数正好要求一个列表 unlink返回值代表成功删除的文件数目 unlink不能用来删除目录,rmdir函数可以。 (7) 重命名文件 rename 'old','new'; rename '/home/hello.sh','/etc/hello.sh'; #将文件移动到其他目录 rename '/home/hello.sh' => '/etc/hello.sh';? 批量修改文件名: foreach my $file (glob "*.old") { ? ? my $newfile = $file; ?? ? ? $newfile =~ s/.old$/.new/; ?# 合并为:(my $newfile = $file) =~ s/.old$/.new/; ? ? if (-e $newfile) ? ? { ? ? ? ? warn "can't rename $file to $newfile: $newfile existsn"; ? ? } ? ? elsif (rename $file => $newfile) ? ? { ? ? ? ? warn "rename $file to $newfile failed: $!n"; ? ? } } (8) 链接与文件 建立硬链接: link 'egg','egg_hardlink' or warn "Can't link chicken to egg: $!"; 建立软链接: symlink 'egg','egg_softlink' or warn "Can't link chicken to egg: $!"; 查看结果: [root@etl10 scott]# ll -ail egg* 2238738 -rw-r--r-- 2 root root 256 Nov ?8 11:01 egg 2238738 -rw-r--r-- 2 root root 256 Nov ?8 11:01 egg_hardlink ?--和egg有相同的inode 同一份内容的两个名字 起到备份的作用 2238690 lrwxrwxrwx 1 root root ? 3 Nov 21 09:51 egg_softlink -> egg ? ?--和egg有不同的inode 要取得符号链接指向的位置,请使用readlink函数。它会返回符号链接指向的位置。 如果参数不是符号链接,则返回undef my $where = readlink 'egg_softlink'; my $perl = readlink '/usr/local/bin/perl'; 这两种链接都可以用unlink移除。 (9) 创建和删除目录 mkdir 'fred',0755 or warn "Cannot make fred directory: $!"; oct()函数,可以强行把字符串当成八进制数据处理,无视它是否以0开头: my $permissions = "0755"; mkdir $name,oct($permissions); 一般下面的情况下,需要使用oct函数: my ($name,$perm) = @ARGV; mkdir $name,oct($perm) or die "cannot create $name: $!"; 如果移除空的目录,可以使用rmdir命令: foreach my $dir (qw(fred barney betty)) { ? ? rmdir $dir or warn "cannot rmdir $dir: $!n"; ? ? } 如果对非空目录调用rmdir函数会导致失败。可以先用unlink删除目录中的内容,再试着删除已经清空的目录。 my $temp_dir = "/tmp/scratch_$$"; mkdir $temp_dir,0700 or die "cannot create $temp_dir: $!"; unlink glob "$temp_dir/* $temp_dir/.*"; rmdir $tempdir; (10) 修改权限 chmod 0755,'fred','barney'; (11) 修改隶属关系 my $user = 1004; ?--指定是必须给定数字的形式 my $group = 100; chown $user,$group,glob "*.o"; 如果处理的不是数字,而是字符串,如下处理: 使用getpwnam函数将用户名转换为用户编号。 使用getgrnam函数将用户组转换为用户组编号。 defined(my $user = getpwnam 'merlyn') or die 'bad user'; #获取merlyn用户名的UID defined(my $group = getpwnam 'users') or die 'bad group'; chown $user,glob '/home/merlyn/*'; (12) 修改时间戳 可以使用utime函数来修改文件的最近修改或访问的时间 它的前两个参数是新的访问时间和更改时间,其余参数就是要修改时间戳的文件名列表。 my $now = time; my $ago = $now - 24 * 60 * 60; utime $now,$ago,glob '*'; #将组后访问时间更改为当前时间,最后修改时间改为一天前 测试1: print "Which directory? (Default is your home directory)"; chomp(my $dir = <STDIN>); if ($dir =~ /As*Z/) { ? ? chdir or die "Can't chdir to your home directory: $!"; } else { ? ? chdir $dir or die "Can't chdir to '$dir' : $!"; } my @files = <*>; #不包含. ..和所有以点开头的文件或目录,如果使用my @files = <.* *>就显示所有的内容,.*显示所有以点号开头的内容。 foreach (@files) #如果上面用<.* *>,则这里使用foreach (sort @files) { ? ? print "$_n"; } 测试2: print "Which directory? (Default is your home directory)"; chomp(my $dir = <STDIN>); if ($dir =~ /As*Z/) { ? ? chdir or die "Can't chdir to your home directory: $!"; } else { ? ? chdir $dir or die "Can't chdir to '$dir' : $!"; } opendir DOT,'.' or die "Can't opendir dot: $!"; foreach (sort readdir DOT) { ? ? #next if /A./; # ?如果跳过文件名以点号开头的文件 ? ? print "$_n"; } 测试3: use File::Basename; use File::Spec; my ($source,$dest) = @ARGV; if (-d $dest) { ? ? my $basename = basename $source; ? ? $dest = File::Spec->catfile($dest,$basename); } rename $source,$dest or die "Can't rename '$source' to ?'$dest': $!n"; 测试4: use File::Basename; use File::Spec; my ($source,$basename); } link $source,$dest or die "Can't link '$source' to ?'$dest': $!n"; 测试5: use File::Basename; use File::Spec; my $symlink = $ARGV[0] eq '-s'; shift @ARGV if $symlink; my ($source,$dest) = @ARGV; if (-d $dest) {? ? ? my $basename = basename $source; ? ? $dest = File::Spec->catfile($dest,$basename); } if ($symlink) { ? ? symlink $source,$dest or die "Can't make soft link from '$source' to '$dest': $!n"; } else { ? ? link $source,$dest or die "Can't make hard link from '$source' to '$dest': $!n"; } 第十四章 字符串与排序 (1) 用index查找字符串? $where = index($big,$small); Perl会在$big字符串中寻找$small字符串首次出现的地方,并返回一个整数表示第一个字符的匹配位置,返回的字符位置是从零算起的。 如果index无法找到,则返回-1 可以加入第三个参数,表明从该参数指定的位置开始寻找子字符串。 使用rindex函数来搜索字符串最后出现的地方,从字符串末尾的地方开始找起: my $last_slash = rindex("/etc/passwd","/"); #值为4 rindex函数也有可选的第三个参数,但这里是用来限定返回值的上限。 (2) 用substr操作子字符串 三个参数:一个原始字符串,一个从零起算的起始位置以及字符串的长度。 my $long = "some very very long string"; my $right = substr($long,index($long,"l")); print "$rightn"; Result: long string 替换的操作: my $string = "Hello,world!"; substr($string,5) = "Goodbye"; #string的值现在为Goodbye,world! 对指定范围的字符串进行操作: 处理字符串的最后20个字符串: substr($string,-20) =~ s/fred/barney/g; substr函数的第四个参数是替换字符串: my $previous_value = substr($string,5,"Goodbye"); 测试1: #!/usr/bin/env perl my $string = "Hello,world!"; my $previous_value = substr($string,"Goodbye"); print "$previous_valuen"; print "$stringn"; Result: Hello ?#返回的是替换之前的字符串 Goodbye,world! #返回的是替换之后的字符串 (3) 用sprintf格式化字符串 sprintf函数与printf有相同的参数,但是它返回的是所请求的字符串,而不会直接打印出来。 好处是可以将格式化后的字符串存放在变量里面以便稍后使用。 **使用sprintf格式化金额数字 sprintf的一种常见用法就是格式化小数点后具有特定精度的数字 my $money = sprintf "%.2f",2.49997; print "$moneyn"; Result: 2.50 测试1: sub big_money { ? ? my $number = sprintf "%.2f",shift @_; ? ? 1 while $number =~ s/^(-?d+)(ddd)/$1,$2/; #对$number数字进行不断的处理,每三个数字中间加入一个逗号 主要执行条件表达式 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #1也可以替换成其他任何合法的代码。 ? ? $number =~ s/^(-?)/$1$/; ? ? print "$numbern"; ? ? $number; ? ?? } big_money(-323243435128172.21212); **非十进制数字字符串的转换 如果字符串是以 特定的十六进制或二进制前缀字符开头的话,oct()函数能聪明地根据该进制进行转换,不过 十六进制字符串必须以0x开头。 **高级排序 排序子程序用来实现自定义的排序方式。 sub by_number { ? ? if ($a < $b)? ? ? { ? ? ? ? -1 ? ? } ? ? elsif ($a > $b) ? ? { ? ? ? ? 1 ? ? } ? ? else ? ? { ? ? ? ? 0 ? ? } } ?? my @result = sort by_number @some_number; 许多排序里面的程序的名字都是以by_开头的,用以说明排序规格。 飞船操作符:<=> ?用来比较数字 这个操作符会比较两个数字并返回-1、0和1,好让它们依数字排序。 上面的代码优化: sub by_number { ? ? $a <=> $b; } 三路字符串比较操作符:cmp ? cmp所提供的顺序和sort默认的排序规则相同。 sub by_code_point { ? ? $a cmp $b; } my $strings = sort by_code_point @any_strings; 不区分大小写的排序: @any_strings = ("Hello",'OK','ff'); sub by_code_point { ? ? "L$a" cmp "L$b"; #强制转换成小写 } my @strings = sort by_code_point @any_strings; print "@stringsn"; 一般来说,要对Unicode字符串排序,都会写成下面: use Unicode::Normalize; sub equivalents? { ? ? NFKD($a) cmp NFKD($a); } 在比较的过程中,我们并没有修改被比较的值。 将整个排序子程序内嵌到排序子程序名的位置即可: my @numbers = sort { $a <=> $b } @some_numbers; 递减的排序子程序: my @numbers = reverse sort { $a <=> $b } @some_numbers; 注:小窍门,比较操作符(<=>,cmp)是短视的,不知道哪个是操作数$a,哪个是操作符$b,只知道哪一个在左边,哪一个在右边,如果我们将 $a和$b对调,比较操作符每次就会得到相反的结果。 my @numbers = sort { $b <=> $a } @some_numbers; **按哈希值排序 my %score = ("barney" => 195,"fred" => 205,"dino" => 30); sub by_score { ? ? $score{$a} <=> $score{$b}; #升序排列 } **按多个键排序 my %score = ("barney" => 195,"dino" => 30,"bamm-bamm" => 195); sub by_score_and_name { ? ? $score{$a} <=> $score{$b} or $a cmp $b; #先根据分数降序排列,分数相同时再按照名字的ASCII码序排列 } my @winners = sort by_score_and_name keys %score; 测试1: 将输入的数字进行排序: my @numbers; push @numbers,split while <>; foreach (sort { $a <=> $b} @numbers) { ? ? printf "%20gn",$_; } [root@etl10 scott]# perl test.pl? 12 34 3 -9 50 050 03 ? ? ? ? ? ? ? ? #以上为输入内容,以下为输出内容 ? ? ? ? ? ? ? ? ? -9 ? ? ? ? ? ? ? ? ? ?3 ? ? ? ? ? ? ? ? ? ?3 ? ? ? ? ? ? ? ? ? 12 ? ? ? ? ? ? ? ? ? 34 ? ? ? ? ? ? ? ? ? 50 ? ? ? ? ? ? ? ? ? 50 测试2: my $keys = sort { "L$last_name{$a]" cmp "L$last_name{$b]" or "L$a" cmp "L$b"} keys %last_name; foreach (@keys) { ? ? print "$last_name{$_},$_n"; } 测试3: print "Please enter a string: "; chomp(my $string = <STDIN>); print "Please enter a substring: "; chomp(my $sub = <STDIN>); my @placles; for (my $pos = -1; ;) { ? ? $pos = index($string,$sub,$pos + 1); ? ? last if $pos == -1; ? ? push @places,$pos; ?? } print "Location of '$sub' in '$string' were: @placesn"; [root@etl10 scott]# perl test.pl? Please enter a string: helloisisgood Please enter a substring: is Location of 'is' in 'helloisisgood' were: 5 7 第十五章 智能匹配与given-when结构 智能匹配是从5.10.0开始出现的,后来Perl 5.10.1版本解决了Perl 5.10.0版本的绝大多数bug。 所以要使用智能匹配,需要使用Perl 5.10.1版本,否则会招致意外。 use 5.010001 #至少是5.10.1版本 (1) 智能匹配操作符 智能匹配操作符~~和绑定操作符=~非常相近,不过~~更能干些,有时可以取代绑定操作符。 print "I found Fred in the name!n" if $name =~ /Fred/; 改用智能匹配操作符代替绑定操作符: use 5.010001; say "I found Fred in the name!" if $name ~~ /Fred/; 实例: 之前方法:兼容性好,但是繁琐 my $flag = 0; foreach my $key (keys %names) { ? ? next unless $key =~ /Fred/; ? ? $flag = $key; ? ? last; ? } print "I found a key matching 'Fred'. It was $flagn" if $flag; 智能匹配的写法为: use 5.010001; %names = ("Fred" => 12,"Name" => 'Hello'); say "I found a key matching 'Fred'!" if %names ~~ /Fred/; #写成这样也是OK的:say "I found a key matching 'Fred'!" if /Fred/ ~~ %names; ? [root@etl10 scott]# perl test.pl? I found a key matching 'Fred'! 比较两个数组的大小: $equal = 0; foreach my $index (0..$#name1) { ? ? last unless $names1[$index] eq $names2([$index]; ? ? $equal++; } print "The arrays have the same elements!n" if $equal == @names1; #只有相等时,才认为两者相同 智能匹配的写法为 use 5.010001; print "The arrays have the same elements!n" if @names1 ~~ @names2;? 判断数字数组中是否含有某个数字: use 5.010001; my $nums = qw( 1 2 34 5 42); my $result = max( @nums ); say "The result [$result] is one of the input values (@nums)" if @nums ~~ $result;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读