2013-05-30 3 views
0
#!/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"; 

[email protected]=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 не допускаются, кроме копирования, перемещения и путисценарий в Perl, чтобы скопировать структуру каталогов от источника к месту назначения

+2

Если вы не можете использовать модули CPAN, это не означает, что вы не можете использовать их реализацию. Посмотрите, например, на [Каталог :: Итератор] (http://search.cpan.org/~sanbeg/Directory-Iterator-1.001/lib/Directory/Iterator.pm). Получайте кредит, в котором должен быть предоставлен кредит. –

+5

Домашнее задание или есть еще одна причина, по которой вы не можете использовать 'cp -r'? – flesk

+0

Также см. Https://metacpan.org/module/File::Copy::Recursive для справки. – simbabque

ответ

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.

Кстати, вы можете переписать find как это, которое, как вы обычно видите его в documentation:

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 находит каждый и каждый файл, каталог, ссылки, или этажерку, расположенный в списке каталогов вы переходите к нему.С каждым предметом он находит в этом каталоге, он передает его на ваш хотел подпрограмма для обработки. A 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, поэтому у вас есть ошибка.

+0

Ваша первая часть кода работает отлично, но если вы можете писать комментарии или объяснять, что вы делаете там, так как я начинаю, я могу понять половину этого, но не полностью. – dhillon

+0

find (sub { return if -f; # Мы хотим только файлы make_path "$ dest_dir/$ File :: Find :: dir" , если только -d "$ dest_dir/$ File :: Find :: dir"; copy $ _, $ dest_dir/$ Файл :: Find :: name или die qq (не удается скопировать «$ File :: Find :: name» в «$ dest_dir»); }, $ source_dir); Может ли кто-нибудь объяснить, что происходит здесь, я борюсь, а hw копирует, даже не используя исходный каталог. – dhillon

+0

Команда 'find' - это немного странный модуль. Подпрограмма _wanted_ вызывается для каждого файла в дереве каталогов. Каждый раз, когда вызывается подпрограмма _wanted_, устанавливаются три переменные: '$ File :: Find :: $ name' устанавливается на полное имя файла,' $ File :: Find :: dir' устанавливается на имя каталог, в котором находится файл, а '$ _' - имя самого файла. Когда вызывается подпрограмма _wanted_, она находится в каталоге этого файла. Таким образом, вы можете получить доступ к файлу через '$ _'. Таким образом, 'return if -f' означает' return if -f $ _', что означает пропустить это, потому что это не файл. –

Смежные вопросы