Как я могу скопировать каталог рекурсивно и отфильтровать имена файлов в Perl?

Это сложное требование, которое, как прокомментировал Гордон Линофф, было бы гораздо проще решить, если бы данные были уже правильно распределены.

Вот подход:

  • Сначала используйте рекурсивный CTE с REGEXP_SUBSTR и CONNECT BY, чтобы разбить строку на строки, используя разделитель запятых
  • Затем разделите каждый строка в 3 столбца, снова с REGEXP_SUBSTR и разделителем пробела
  • Затем используйте функции окна оракула DENSE_RANK и KEEP, чтобы изолировать соответствующую строку

Предполагая, что данные поступают из столбца str в таблице my_table:

WITH 
    cte0 AS (
        SELECT TRIM(REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL)) str
        FROM my_table
        CONNECT BY INSTR(str, ',', 1, LEVEL - 1) > 0
    ),
    cte1 AS (
        SELECT 
            TO_DATE(REGEXP_SUBSTR(str, '\S+', 1, 1), 'yyyy-mm-dd') dt,
            REGEXP_SUBSTR(str, '\S+', 1, 2) val1,
            REGEXP_SUBSTR(str, '\S+', 1, 3) val2
        FROM cte0
        ORDER BY 1 DESC
    )
SELECT 
    MIN(dt)   keep (dense_rank first order by dt) as dt,
    MIN(val1) keep (dense_rank first order by dt) as val1,
    MIN(val2) keep (dense_rank first order by dt) as val2
FROM cte1
WHERE dt > TO_DATE(?, 'yyyy-mm-dd')

... где ? - дата ввода.

* db <> скрипка здесь

 with 
     data as  (
         SELECT
             '2015/04/01 11 GG, 2015/08/03 78 KK, 2012/12/12 44 TT, 2015/09/01 77 YY, 2015/09/01 88 ZZ' str
         FROM DUAL
     ),
     cte0 AS (
         SELECT TRIM(REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL)) str
         FROM data
         CONNECT BY INSTR(str, ',', 1, LEVEL - 1) > 0
     ),
     cte1 AS (
         SELECT 
             TO_DATE(REGEXP_SUBSTR(str, '\S+', 1, 1), 'yyyy-mm-dd') dt,
             REGEXP_SUBSTR(str, '\S+', 1, 2) val1,
             REGEXP_SUBSTR(str, '\S+', 1, 3) val2
         FROM cte0
         ORDER BY 1 DESC
     )
 SELECT 
     min(dt) keep (dense_rank first order by dt) as dt,
     min(val1) keep (dense_rank first order by dt) as val1,
     min(val2) keep (dense_rank first order by dt) as val2
 FROM cte1
 WHERE dt > TO_DATE('2015-08-01', 'yyyy-mm-dd')


-------------------------
 DT        | VAL1 | VAL2
 :-------- | :--- | :---
 03-AUG-15 | 78   | KK  

12
задан brian d foy 23 October 2008 в 01:07
поделиться

5 ответов

Я сделал бы что-то вроде этого:

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;
}
11
ответ дан 2 December 2019 в 05:42
поделиться

Другой опцией является File::Xcopy. Как имя говорит, оно более или менее эмулирует команду 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");
9
ответ дан 2 December 2019 в 05:42
поделиться

Если Вы, оказывается, находитесь на подобной Unix ОС и имеете доступ к rsync (1), необходимо использовать это (например, через system()).

File::Copy Perl немного повреждается (это не копирует полномочия в системах Unix, например), поэтому если Вы не хотите использовать свои системные инструменты, взгляд на CPAN. Возможно, File::Copy::Recursive мог быть полезным, но я не вижу, что любой исключает опции. Я надеюсь, что у кого-то еще есть лучшая идея.

5
ответ дан 2 December 2019 в 05:42
поделиться

Я не знаю, как сделать исключение с копией, но Вы могли обработать что-то вроде:

ls -R1 | grep -v <regex to exclude> | awk '{printf("cp %s /destination/path",$1)}' | /bin/sh
1
ответ дан 2 December 2019 в 05:42
поделиться

Классический ответ использовал бы'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'если это - то, что Вы хотите.

1
ответ дан 2 December 2019 в 05:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: