Perl语言入门笔记 第十三章 目录操作
=pod 第十三章 目录操作 在目录树中移动: 程序运行时会以自己的工作目录作为相对路径的起点,也就是说,当我们提及fred这个文件时,其实指的是"当前工作目录下的fred" chdir '/etc' or die "Cannot chdir to /etc: $!"; 如果掉用chdir时不加参数,perl会猜想你要回到自己的用户主目录并试着将工作目录设成主目录 chdir后面跟路径不能是以~开头的 文件名通配: 文件名通配(glob) echo *.pl 会输出当前文件下所有.pl文件,没有.pl文件的话,就输出*.pl 下面程序只是简单输出所有命令行参数: foreach $arg (@ARGV) { print "one arg is $arg\n"; } 用的时候,perl ex13_1.pl *.pl 输出: one arg is ex12_1.pl one arg is ex12_test.pl one arg is ex13_1.pl one arg is ex13_test.pl one arg is ex5_1.pl one arg is ex5_test.pl one arg is ex6_1.pl one arg is ex6_test.pl glob操作符 my @all_files = glob '*'; #文件名按字母排序 my @pm_files = glob '*.pm'; 文件名通配的另一种语法: my @all_files = <*>; #效果和这样的写法完全一致:my @all_files = glob '*'; my @dir_files = <$dir/* $dir/.*>; my @files = <FRED/*>; #文件名通配操作 my @lines = <FRED>; #从文件句柄读取 my @lines = <$fred>; #从文件句柄读取 my $name = 'FRED'; my @files = <$name>; #文件名通配操作 readline: my $name = 'FRED'; my @lines = readline FRED; #从FRED读取 my @lines = readline $name; #从FRED读取 目录句柄: 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 if $file\n"; } closedir $dh; 也可以是裸字作为文件句柄,如DIR 目录句柄遍历文件时把.,..,.xx.xx也匹配了进来,所以处理时要避开这些不合要求的文件, 跳过.开头的文件; next if $name =~ /^\./; 去除.和..; next if $name eq '.' or $name eq '..'; open my $somedir, $dirname or die "Cannot open $dirname: $!"; while(my $name = readdir $somedir) { next if $name =~ /^\./; #跳过名称以点开头的文件 $name = "$dirname/$name"; #拼合为完整的路径 next unless -f $name and -r $name; #只需要可读的文件 } 为了让程序更具有可移植性,可以用File::Spec::Functions模块构造用于本地系统的合适文件名: use File::Spec::Functions; 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; } 若是没有接上路径,文件测试操作符会在当前目录下查找文件,而不是在$dirname制定的目录下,这是使用目录句柄时最常犯的错误。 递归访问目录: CPAN上的File::Find::Rule和File::Finder,都在File::Fine基础上的,提供了更为直观,易用的用户界面 文件和目录的操作: 删除文件: unlink操作符,指定要删除的文件列表 unlink 'slate', 'bedrock', 'lava'; #这会把三个文件放进粉碎机,从此消失在系统中。 unlink glob '*.o'; #glob得到一个列表,unlink删除一个列表 unlink的返回值是代表成功删除的文件数目。 my $successful = unlink "slate", "bedrock", "lava"; print "I deleted $successful file(s) just down\n"; foreach my $file (qw(slate bedrock lava)) { unlink $file or warn "failed on $file: $!\n"; } 重命名文件: rename 'old', 'new'; rename 'over_there/some/place/some_file' => 'some_file'; 和大部分调用操作系统功能的函数一样,rename执行失败时返回假,并将操作系统返回的错误信息存到$!里,从而让你可以用ordie或orwarn来向用户汇报问题。 批量将.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"; } } 链接与文件: mounted volume link 'chicked', 'egg' or warn "Can't link chicked to egg: $!"; 软链接: symlink 'dodgson', 'carroll' or warn "Can't symlink dodgson to carroll: $!"; 要取得符号链接指向的位置,请使用readlink函数,他会返回符号链接指向的位置,如果参数不是符号链接,则返回undef: my $where = readlink 'carrol'; #得到'dodgson' my $perl = readlink '/usr/local/bin/perl'; #告诉你实际的perl程序究竟躲在何处 这两种链接都可以用ulink移除,你现在该了解它取这个名字的含义,unlink只是从目录里移除该文件名的链接条目,并将它的链接数递减,必要时再释放inode 创建和删除目录: 要在现有的目录下创建目录是件容易的事,只需调用mkdir函数即可: mkdir 'fred', 0755 or warn "Cannot make fred directory: $!"; mkdir $name, oct($permissions); my ($name, $perm) = @ARGV; mkdir $name, oct($perm) or die "Cannot create $name: $!"; 删除目录: my $temp_dir = "/tmp/scratch_$$"; mkdir $temp_dir, 0700 or die "Cannot create $temp_dir: $!"; #将临时目录$temp_dir作为所有临时文件存放的场所 ... unlink glob "$temp_dir/* $temp_dir/.*"; #先删除文件夹中的内容 rmdir $temp_dir; #再删除文件夹 $$:pid存在$$中 如果我们在临时目录里创建了子目录,那么unlink操作符在处理它们时将会失败,rmdir也会跟着失败,请参考perl自带的File::Path模块,里面的rmtree函数提供了比较完整的解决方案。 如果你去确实想要创建一个临时文件或目录,可以用perl自带的File::Temp模块 修改权限: chmod 0755, 'fred', 'barney'; 和许多其他操作系统接口函数一样,chmod会返回成功更改的条目的数量,哪怕只有一个参数,它也会在失败时将$!设成合力的错误信息,第一个参数代表Unix的权限值,unix的chmod命令能接受用符号表示的权限(例如+x或go=u-w),但是chmod函数并不接受这类参数。 修改隶属关系: 只要操作系统允许,你可以用chown函数修改一系列文件的拥有者以及其所属组,拥有者和所属组会被同时更改,并且在指定时必须给出数字形式的用户标示符及组标示符。 my $user = 1004; my $group = 100; chown $user, $group, glob '*.o'; 如果要处理的不是数字,而是像merlyn这样的字符串呢?只要用getpwnam函数将用户名转换成用户编号,再用相应的getgrnam函数把用户名转换成组编号: defined(my $user = getpwnam 'merlyn') or die 'bad user'; defined(my $grpup = getgrnam 'users') or die 'bad group'; chown $user, $group, glob '/home/merlyn/*'; 成功操作后,chown函数会返回受影响的文件数量,在错误发生时会在$!中设定出错信息。 修改时间戳: 用utime函数来修改,它的前两个阐述是新的访问时间和更改时间,其余参数就是要修改时间戳的文件名列表,时间格式采用的是内部时间戳的格式(stat和lstat函数返回值类型) my $now = time; my $ago = $now - 24 * 60 * 60; #一天的秒数 utime $now, $ago, $glob '*'; #将最后访问时间改为当前时间,最后修改时间改为一天前 =cut
简单练习:
#!/usr/bin/perl -w use strict; #use autodie; #use File::HomeDir; #第三方模块,不管在什么操作系统上都能进入指定用户的主目录 system 'ls'; chdir '/Users/it-0003005'; =pod eval { chdir '~/'; }; #这里有分号,eval里面的程序发生fatal error 但是并不会结束程序,还会继续执行下去 =cut print "+++++++++++++++++++++++++++++++++++++++++++++++\n"; system 'ls'; print "+++++++++++++++++++++++++++++++++++++++++++++++\n"; foreach my $arg (@ARGV) { print "one arg is $arg\n"; } print "+++++++++++++++++++++++++++++++++++++++++++++++\n"; my @allFiles = glob '*'; #取出的文件文件并没有\n foreach my $value (@allFiles) { print $value, "\n"; } &search_file('/Users', '.+\.py$'); sub search_file { my ($dir, $partInfo) = @_; #print $partInfo, "\n"; opendir my $dh, $dir or die "Cannot open dir $dir\n"; my @files = readdir $dh; #标量上下文和列表上下文 foreach my $file (@files) { my $filePath = "$dir/$file"; if(($file =~ m#$partInfo#i) and (-f $filePath)) { print "$filePath\n"; } if((-d $filePath) and ($file ne '.') and ($file ne '..')) { &search_file($filePath, $partInfo); } } }
不负自己