如何递归复制目录并在 Perl 中过滤文件名?

Posted

技术标签:

【中文标题】如何递归复制目录并在 Perl 中过滤文件名?【英文标题】:How can I copy a directory recursively and filter filenames in Perl? 【发布时间】:2010-09-18 15:53:54 【问题描述】:

如何复制包含子目录的目录,不包括与 Windows 系统上的某个正则表达式匹配的文件或目录?

【问题讨论】:

【参考方案1】:

我会这样做:

use File::Copy;
sub copy_recursively 
    my ($from_dir, $to_dir, $regex) = @_;
    opendir my($dh), $from_dir or die "Could not open dir '$from_dir': $!";
    for my $entry (readdir $dh) 
        next if $entry =~ /$regex/;
        my $source = "$from_dir/$entry";
        my $destination = "$to_dir/$entry";
        if (-d $source) 
            mkdir $destination or die "mkdir '$destination' failed: $!" if not -e $destination;
            copy_recursively($source, $destination, $regex);
         else 
            copy($source, $destination) or die "copy failed: $!";
        
    
    closedir $dh;
    return;

【讨论】:

如果您的 $regexp 不匹配“。”,我认为您有问题(无限循环)。或 "..",它们是 readdir 返回的 $entry 的前两个值。如果您的 $to_dir 不存在,并且 $source 确实是一个目录,则 mkdir 将失败,我建议改用 mkpath。 。和 .. 在 Windows AFAIK 上不是问题,所以这不应该是问题,但为了可移植性,你是对的,最好将它们过滤掉。至于 mkpath:我个人认为这种情况应该会报错,但这是个人喜好问题。【参考方案2】:

另一个选项是 File::Xcopy。顾名思义,它或多或少地模拟了 windows xcopy 命令,包括它的过滤和递归选项。

来自文档:

    use File::Xcopy;

    my $fx = new File::Xcopy; 
    $fx->from_dir("/from/dir");
    $fx->to_dir("/to/dir");
    $fx->fn_pat('(\.pl|\.txt)$');  # files with pl & txt extensions
    $fx->param('s',1);             # search recursively to sub dirs
    $fx->param('verbose',1);       # search recursively to sub dirs
    $fx->param('log_file','/my/log/file.log');
    my ($sr, $rr) = $fx->get_stat; 
    $fx->xcopy;                    # or
    $fx->execute('copy'); 

    # the same with short name
    $fx->xcp("from_dir", "to_dir", "file_name_pattern");

【讨论】:

【参考方案3】:

如果您碰巧在一个类 Unix 操作系统上并且可以访问 rsync (1),您应该使用它(例如通过 system())。

Perl 的 File::Copy 有点损坏(例如,它不会在 Unix 系统上复制权限),所以如果您不想使用系统工具,请查看 CPAN。也许File::Copy::Recursive 可能有用,但我没有看到任何排除选项。我希望其他人有更好的主意。

【讨论】:

【参考方案4】:

我不知道如何对副本进行排除,但您可以按照以下方式进行处理:

ls -R1 | grep -v <regex to exclude> | awk 'printf("cp %s /destination/path",$1)' | /bin/sh

【讨论】:

【参考方案5】:

一个经典的答案是使用'cpio -p':

(cd $SOURCE_DIR; find . -type f -print) |
perl -ne 'print unless m/<regex-goes-here>/' |
cpio -pd $TARGET_DIR

'cpio' 命令处理实际的复制,包括权限保留。 'cd $SOURCE_DIR; find . ...' 的技巧是从名称中删除源路径的前导部分。调用 'find' 的唯一问题是它不会遵循符号链接。如果这是您想要的,您需要添加“-follow”。

【讨论】:

以上是关于如何递归复制目录并在 Perl 中过滤文件名?的主要内容,如果未能解决你的问题,请参考以下文章

java 如何递归遍历多重目录下的指定格式文件复制到目标目录并改格式

如何循环遍历 Perl 目录中的文件? [复制]

如何递归地读出 Perl 中的目录?

perl 递归的删除目录和目录中的文件

如何在bash中递归复制所有目录和文件?

如何在 PHP 中递归删除目录及其全部内容(文件 + 子目录)? [复制]