#!/usr/bin/perl -w
use File::Copy;
use strict;
my $i= "0";
my $j= "1";
my $source_directory = $ARGV[$i];
my $target_directory = $ARGV[$j];
#print $source_directory,"\n";
#print $target_directory,"\n";
my@list=process_files ($source_directory);
print "remaninign files\n";
print @list;
# Accepts one argument: the full path to a directory.
# Returns: A list of files that reside in that path.
sub process_files {
my $path = shift;
opendir (DIR, $path)
or die "Unable to open $path: $!";
# We are just chaining the grep and map from
# the previous example.
# You'll see this often, so pay attention ;)
# This is the same as:
# LIST = map(EXP, grep(EXP, readdir()))
my @files =
# Third: Prepend the full path
map { $path . '/' . $_}
# Second: take out '.' and '..'
grep { !/^\.{1,2}$/ }
# First: get all files
readdir (DIR);
closedir (DIR);
for (@files) {
if (-d $_) {
# Add all of the new files from this directory
# (and its subdirectories, and so on... if any)
push @files, process_files ($_);
} else { #print @files,"\n";
# for(@files)
while(@files)
{
my $input= pop @files;
print $input,"\n";
copy($input,$target_directory);
}
}
# NOTE: we're returning the list of files
return @files;
}
}
这基本上是从源到目的地复制文件,但我需要一些指导如何 复制目录也是如此。这里要注意的主要事项是除了复制,移动和路径
之外,不允许使用CPAN模块答案 0 :(得分:2)
为什么不使用File::Find来完成目录结构,而不是滚动自己的目录处理冒险。
#! /usr/bin/env perl
use :5.10;
use warnings;
use File::Find;
use File::Path qw(make_path);
use File::Copy;
use Cwd;
# The first two arguments are source and dest
# 'shift' pops those arguments off the front of
# the @ARGV list, and returns what was removed
# I use "cwd" to get the current working directory
# and prepend that to $dest_dir. That way, $dest_dir
# is in correct relationship to my input parameter.
my $source_dir = shift;
my $dest_dir = cwd . "/" . shift;
# I change into my $source_dir, so the $source_dir
# directory isn't in the file name when I find them.
chdir $source_dir
or die qq(Cannot change into "$source_dir");;
find ( sub {
return unless -f; #We want files only
make_path "$dest_dir/$File::Find::dir"
unless -d "$dest_dir/$File::Find::dir";
copy "$_", "$dest_dir/$File::Find::dir"
or die qq(Can't copy "$File::Find::name" to "$dest_dir/$File::Find::dir");
}, ".");
现在,您不需要process_files
子例程。您让File::Find::find
处理为您复制目录。
顺便说一句,您可以像documentation那样重写find
这就是您通常在{{3}}中看到的内容:
find ( \&wanted, ".");
sub wanted {
return unless -f; #We want files only
make_path "$dest_dir/$File::Find::dir"
unless -d "$dest_dir/$File::Find::dir";
copy "$_", "$dest_dir/$File::Find::dir"
or die qq(Can't copy "$File::Find::name" to "$dest_dir/$File::Find::dir");
}
我更喜欢将想要的子例程嵌入到我的find
命令中,因为我认为它看起来更好。首先,它保证想要的子例程与find
命令一起保存。你不必看两个不同的地方看看发生了什么。
此外,find
命令倾向于吞并整个程序。想象一下,我在哪里获得文件列表并对它们进行一些复杂的处理。整个程序最终可以在wanted
子程序中。为避免这种情况,您只需创建一个要操作的文件数组,然后在程序中对它们进行操作:
...
my @file_list;
find ( \&wanted, "$source_dir" );
for my $file ( @file_list ) {
...
}
sub wanted {
return unless -f;
push @file_list, $File::Find::name;
}
我发现这是编程憎恶。首先,find
发生了什么?它正在修改我的@file_list
,但是怎么样? find
命令中没有提到@file_list
的位置。它在做什么?
然后在我的程序结束时,这个sub wanted
函数以全局方式使用变量@file_list
。这是糟糕的编程习惯。
将我的子程序直接嵌入到我的find
命令中解决了许多问题:
my @file_list;
find ( sub {
return unless -f;
push @file_list;
}, $source_dir );
for my $file ( @file_list ) {
...
}
这看起来更好。我可以看到@file_list
命令正在直接操作find
。另外,那个讨厌的想要的子程序已经从我的程序结束时消失了。它'完全相同的代码。它看起来更好。
让我们了解find
命令正在做什么以及它如何与wanted
子例程一起使用:
find
命令查找传递给它的目录列表中的每个文件,目录,链接或其他内容。对于在该目录中找到的每个项,它会将其传递给想要的子例程进行处理。 return
离开想要的子例程,并允许find
获取下一个项目。
每次调用想要的子例程时,find
都会设置三个变量:
$File::Find::name
:找到的项目名称,附带完整路径。$File::Find::dir
:找到项目的目录名称。$_
:没有目录名称的项目名称。在Perl中,$_
变量非常特殊。它是许多命令的默认变量。也就是说,您执行命令,并且不给它使用变量,该命令将使用$_
。例如:
print
打印出$_
return if -f;
与说这句话相同:
if ( -f $_ ) {
return;
}
这个for
循环:
for ( @file_list ) {
...
}
与此相同:
for $_ ( @file_list ) {
...
}
通常,我会避开默认变量。它的范围是全球性的,并不总是显而易见的。但是,在某些情况下我会使用它,因为它确实澄清了程序的含义:
return unless -f;
在我的想要的功能中非常明显。我退出想要的子例程,除非我交给了一个文件。这是另一个:
return unless /\.txt$/;
除非项目以'.txt'结尾,否则这将退出想要的功能。
我希望这能澄清我的计划正在做什么。另外,我在使用它时消除了一些错误。我错误地将$File::Find::dir
误导为$File::Find::name
,这就是您收到错误的原因。