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);
        }
    }
}


posted @ 2015-09-21 02:01  笑面浮屠  阅读(324)  评论(0编辑  收藏  举报