How do I copy a directory including sub directories excluding files or directories that match a certain regex on a Windows system?
If you want to get content of given directory, and only it (i.e. no subdirectories), the best way is to use opendir/readdir/closedir: opendir my $dir, "/some/path" or die "Cannot open directory: $!"; my @files = readdir $dir; closedir $dir; You can also use: my @files = glob( $dir .
In order to copy the content of a directory recursively, you have to use the “cp” command with the “-R” option and specify the source directory followed by a wildcard character.
Recursive means that cp copies the contents of directories, and if a directory has subdirectories they are copied (recursively) too. Without -R , the cp command skips directories.
I'd do something like this:
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;
}
Another option is File::Xcopy. As the name says, it more-or-less emulates the windows xcopy command, including its filtering and recursive options.
From the documentation:
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");
If you happen to be on a Unix-like OS and have access to rsync (1)
, you should use that (for example through system()
).
Perl's File::Copy is a bit broken (it doesn't copy permissions on Unix systems, for example), so if you don't want to use your system tools, look at CPAN. Maybe File::Copy::Recursive could be of use, but I don't see any exclude options. I hope somebody else has a better idea.
I don't know how to do an exclusion with a copy, but you could work something up along the lines of:
ls -R1 | grep -v <regex to exclude> | awk '{printf("cp %s /destination/path",$1)}' | /bin/sh
A classic answer would use 'cpio -p
':
(cd $SOURCE_DIR; find . -type f -print) |
perl -ne 'print unless m/<regex-goes-here>/' |
cpio -pd $TARGET_DIR
The 'cpio
' command deals with the actual copying, including permission preservation. The trick of 'cd $SOURCE_DIR; find . ...
' deals with removing the leading part of the source path from the names. The only problem with that invocation of 'find
' is that it won't follow symlinks; you need to add '-follow
' if that's what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With