第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

從包含數(shù)百萬(wàn)個(gè)文件的目錄 (bash/python/perl) 中通過(guò)精確匹配有效地查找數(shù)千個(gè)文件

從包含數(shù)百萬(wàn)個(gè)文件的目錄 (bash/python/perl) 中通過(guò)精確匹配有效地查找數(shù)千個(gè)文件

呼喚遠(yuǎn)方 2022-11-24 15:24:25
我在 Linux 上,我試圖從包含數(shù)百萬(wàn)個(gè)文件的目錄 (SOURCE_DIR) 中查找數(shù)千個(gè)文件。我有一個(gè)我需要查找的文件名列表,存儲(chǔ)在一個(gè)文本文件 (FILE_LIST) 中。該文件的每一行都包含一個(gè)名稱,對(duì)應(yīng)于 SOURCE_DIR 中的一個(gè)文件,文件中有數(shù)千行。## FILE_LIST contain single word file names, each per line#Name0001#Name0002#..#Name9999我想將文件復(fù)制到另一個(gè)目錄 (DESTINATION_DIR)。我寫(xiě)了下面的循環(huán),里面有個(gè)循環(huán)一個(gè)一個(gè)找。#!/bin/bashFILE_LIST='file.list'## FILE_LIST contain single word file names, each per line#Name0001#Name0002#..#Name9999SOURCE_DIR='/path/to/source/files' # Contain millions of files in sub-directoriesDESTINATION_DIR='/path/to/destination/files' # Files will be copied to herewhile read FILE_NAMEdo    echo $FILE_NAME    for FILE_NAME_WITH_PATH in `find SOURCE_DIR -maxdepth 3 -name "$FILE_NAME*" -type f -exec readlink -f {} \;`;     do         echo $FILE        cp -pv $FILE_NAME_WITH_PATH $DESTINATION_DIR;     donedone < $FILE_LIST這個(gè)循環(huán)花費(fèi)了很多時(shí)間,我想知道是否有更好的方法來(lái)實(shí)現(xiàn)我的目標(biāo)。我進(jìn)行了搜索,但沒(méi)有找到解決我的問(wèn)題的方法。如果已經(jīng)存在,請(qǐng)直接告訴我解決方案,或者請(qǐng)建議對(duì)上述代碼進(jìn)行任何調(diào)整。如果有另一種方法甚至是 python/perl 解決方案,我也很好。感謝您的時(shí)間和幫助!
查看完整描述

4 回答

?
泛舟湖上清波郎朗

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超3個(gè)贊

注意   下面添加的處理不同目錄中相同名稱的代碼


需要找到要復(fù)制的文件,因?yàn)樗鼈儧](méi)有給出路徑(不知道它們?cè)谀膫€(gè)目錄中),但是重新搜索每個(gè)文件非常浪費(fèi),大大增加了復(fù)雜性。


相反,首先為每個(gè)文件名構(gòu)建一個(gè)具有完整路徑名的散列。


一種方法,使用 Perl,利用快速核心模塊File::Find


use warnings;

use strict;

use feature 'say';


use File::Find;

use File::Copy qw(copy);


my $source_dir = shift // '/path/to/source';  # give at invocation or default


my $copy_to_dir = '/path/to/destination';


my $file_list = 'file_list_to_copy.txt';  

open my $fh, '<', $file_list or die "Can't open $file_list: $!";

my @files = <$fh>;

chomp @files;



my %fqn;    

find( sub { $fqn{$_} = $File::Find::name  unless -d }, $source_dir );


# Now copy the ones from the list to the given location        

foreach my $fname (@files) { 

    copy $fqn{$fname}, $copy_to_dir  

        or do { 

            warn "Can't copy $fqn{$fname} to $copy_to_dir: $!";

            next;

        };

}

剩下的問(wèn)題是關(guān)于可能存在于多個(gè)目錄中的文件名,但是我們需要得到一個(gè)規(guī)則來(lái)決定接下來(lái)要做什么。?


我忽略了問(wèn)題中使用的最大深度,因?yàn)樗鼰o(wú)法解釋并且在我看來(lái)是與極端運(yùn)行時(shí)相關(guān)的修復(fù)(?)。此外,文件被復(fù)制到一個(gè)“平面”結(jié)構(gòu)中(不恢復(fù)其原始層次結(jié)構(gòu)),從問(wèn)題中得到提示。


最后,我只跳過(guò)目錄,而其他各種文件類型都有自己的問(wèn)題(復(fù)制鏈接需要小心)。要僅接受普通文件,請(qǐng)更改unless -d 為if -f.


?澄清說(shuō),確實(shí),不同目錄中可能存在同名文件。那些應(yīng)該復(fù)制到相同的名稱,在擴(kuò)展名之前以序號(hào)為后綴。


為此,我們需要檢查一個(gè)名稱是否已經(jīng)存在,并在構(gòu)建哈希時(shí)跟蹤重復(fù)的名稱,因此這將花費(fèi)更長(zhǎng)的時(shí)間。那么如何解釋重名有一個(gè)小難題呢?我在 arrayrefs 中使用另一個(gè)哈希值,其中只保留了被欺騙的名稱? ;這簡(jiǎn)化并加快了工作的兩個(gè)部分。


my (%fqn, %dupe_names);

find( sub {

    return if -d;

    (exists $fqn{$_})

        ? push( @{ $dupe_names{$_} }, $File::Find::name )

        : ( $fqn{$_} = $File::Find::name );

}, $source_dir );

令我驚訝的是,即使現(xiàn)在對(duì)每個(gè)項(xiàng)目運(yùn)行測(cè)試,它的運(yùn)行速度也比不考慮重復(fù)名稱的代碼慢一點(diǎn)點(diǎn),在 25 萬(wàn)個(gè)文件上分布在一個(gè)龐大的層次結(jié)構(gòu)中。


三元運(yùn)算符中賦值周圍的括號(hào)是必需的,因?yàn)檫\(yùn)算符可能被賦值給(如果最后兩個(gè)參數(shù)是有效的“左值”,就像它們?cè)谶@里一樣),因此需要小心分支內(nèi)的賦值。


然后在%fqn按照帖子的主要部分復(fù)制之后,還復(fù)制其他同名文件。我們需要分解文件名以便在之前添加枚舉.ext;我使用核心File::Basename


use File::Basename qw(fileparse);


foreach my $fname (@files) { 

    next if not exists $dupe_names{$fname};  # no dupe (and copied already)

    my $cnt = 1;

    foreach my $fqn (@{$dupe_names{$fname}}) { 

        my ($name, $path, $ext) = fileparse($fqn, qr/\.[^.]*/); 

        copy $fqn, "$copy_to_dir/${name}_$cnt$ext";

            or do { 

                warn "Can't copy $fqn to $copy_to_dir: $!";

                next;

            };

        ++$cnt;

    }

}

(已完成基本測(cè)試,但僅此而已)


我可能會(huì)使用undef而不是$path上面的方法來(lái)指示該路徑未使用(同時(shí)這也避免了分配和填充標(biāo)量),但為了那些不熟悉模塊的子返回的內(nèi)容的人清楚,我將其保留為這種方式。


筆記。   對(duì)于具有重復(fù)項(xiàng)的文件,將有副本fname.ext、fname_1.ext等。如果您希望將它們?nèi)烤幦胨饕?,則首先將fname.ext(在目標(biāo)位置,它已通過(guò) 復(fù)制%fqn)重命名為fname_1.ext,并將計(jì)數(shù)器初始化更改為my $cnt = 2;。


?請(qǐng)注意,這些文件不一定是相同的文件。


查看完整回答
反對(duì) 回復(fù) 2022-11-24
?
智慧大石

TA貢獻(xiàn)1946條經(jīng)驗(yàn) 獲得超3個(gè)贊

我懷疑速度問(wèn)題(至少部分)來(lái)自您的嵌套循環(huán) - 對(duì)于每個(gè)FILE_NAME,您都在運(yùn)行 afind并循環(huán)其結(jié)果。下面的 Perl 解決方案使用動(dòng)態(tài)構(gòu)建正則表達(dá)式的技術(shù)(適用于大型列表,我已經(jīng)在 100k+ 單詞的列表上進(jìn)行了測(cè)試),這樣你只需要遍歷文件一次并讓正則表達(dá)式引擎處理其余部分;這相當(dāng)快。


請(qǐng)注意,根據(jù)我對(duì)您的腳本的閱讀,我做了幾個(gè)假設(shè):您希望模式在文件名的開(kāi)頭區(qū)分大小寫(xiě),并且您希望在目標(biāo)中重新創(chuàng)建與源相同的目錄結(jié)構(gòu)(設(shè)置$KEEP_DIR_STRUCT=0如果你不想要這個(gè))。此外,我正在使用不完全是最佳實(shí)踐的解決方案,find而不是使用 Perl 自己的解決方案,F(xiàn)ile::Find因?yàn)樗梢愿菀椎貙?shí)現(xiàn)您正在使用的相同選項(xiàng)(例如-maxdepth 3) - 但它應(yīng)該可以正常工作,除非有名稱中帶有換行符的任何文件。


該腳本僅使用核心模塊,因此您應(yīng)該已經(jīng)安裝了它們。


#!/usr/bin/env perl

use warnings;

use strict;

use File::Basename qw/fileparse/;

use File::Spec::Functions qw/catfile abs2rel/;

use File::Path qw/make_path/;

use File::Copy qw/copy/;


# user settings

my $FILE_LIST='file.list';

my $SOURCE_DIR='/tmp/source';

my $DESTINATION_DIR='/tmp/dest';

my $KEEP_DIR_STRUCT=1;

my $DEBUG=1;


# read the file list

open my $fh, '<', $FILE_LIST or die "$FILE_LIST: $!";

chomp( my @files = <$fh> );

close $fh;


# build a regular expression from the list of filenames

# explained at: https://www.perlmonks.org/?node_id=1179840

my ($regex) = map { qr/^(?:$_)/ } join '|', map {quotemeta}

    sort { length $b <=> length $a or $a cmp $b } @files;


# prep dest dir

make_path($DESTINATION_DIR, { verbose => $DEBUG } );


# use external "find"

my @cmd = ('find',$SOURCE_DIR,qw{ -maxdepth 3 -type f -exec readlink -f {} ; });

open my $cmd, '-|', @cmd or die $!;

while ( my $srcfile = <$cmd> ) {

    chomp($srcfile);

    my $basename = fileparse($srcfile);

    # only interested in files that match the pattern

    next unless $basename =~ /$regex/;

    my $newname;

    if ($KEEP_DIR_STRUCT) {

        # get filename relative to the source directory

        my $relname = abs2rel $srcfile, $SOURCE_DIR;

        # build new filename in destination directory

        $newname = catfile $DESTINATION_DIR, $relname;

        # create the directories in the destination (if necessary)

        my (undef, $dirs) = fileparse($newname);

        make_path($dirs, { verbose => $DEBUG } );

    }

    else {

        # flatten the directory structure

        $newname = catfile $DESTINATION_DIR, $basename;

        # warn about potential naming conflicts

        warn "overwriting $newname with $srcfile\n" if -e $newname;

    }

    # copy the file

    print STDERR "cp $srcfile $newname\n" if $DEBUG;

    copy($srcfile, $newname) or die "copy('$srcfile', '$newname'): $!";

}

close $cmd or die "external command failed: ".($!||$?);

您可能還想考慮使用硬鏈接而不是復(fù)制文件。


查看完整回答
反對(duì) 回復(fù) 2022-11-24
?
暮色呼如

TA貢獻(xiàn)1853條經(jīng)驗(yàn) 獲得超9個(gè)贊

和rsync

我不知道這對(duì)于數(shù)百萬(wàn)個(gè)文件會(huì)有多快,但這是一種使用rsync.


按以下格式設(shè)置您的格式file.list(例如:如 with $ cat file.list | awk '{print "+ *" $0}')。


+ *Name0001

+ *Name0002

...

+ *Name9999

在命令中file.list使用--include=from選項(xiàng)調(diào)用:rsync


$ rsync -v -r --dry-run --filter="+ **/" --include-from=/tmp/file.list --filter="- *" /path/to/source/files /path/to/destination/files

選項(xiàng)說(shuō)明:


-v                  : Show verbose info.

-r                  : Traverse directories when searching for files to copy.

--dry-run           : Remove this if preview looks okay

--filter="+ *./"    : Pattern to include all directories in search

--include-from=/tmp/file.list  : Include patterns from file.

--filter="- *"      : Exclude everything that didn't match previous patterns.

期權(quán)訂單很重要。


--dry-run如果詳細(xì)信息看起來(lái)可以接受,請(qǐng)刪除。


測(cè)試rsync版本 3.1.3。


查看完整回答
反對(duì) 回復(fù) 2022-11-24
?
HUX布斯

TA貢獻(xiàn)1876條經(jīng)驗(yàn) 獲得超6個(gè)贊

這是帶有 的 bashv4+ 解決方案find,但不確定速度。


#!/usr/bin/env bash


files=file.list

sourcedir=/path/to/source/files

destination=/path/to/destination/files

mapfile -t lists < "$files"

total=${#lists[*]}


while IFS= read -rd '' files; do

  counter=0

  while ((counter < total)); do

    if [[ $files == *"${lists[counter]}" ]]; then

      echo cp -v "$files" "$destination" && unset 'lists[counter]' && break

    fi

    ((counter++))

  done

  lists=("${lists[@]}")

  total=${#lists[*]}

  (( ! total )) && break  ##: if the lists is already emtpy/zero, break.

done < <(find "$sourcedir" -type f -print0)

如果在 file.list 和 source_directory 中的文件中找到匹配項(xiàng),則innerbreak將退出內(nèi)部循環(huán),因此它不會(huì)處理 file.list 直到最后,它會(huì)刪除"${lists[@]}"(這是一個(gè)數(shù)組)中的條目,unset所以下一個(gè)內(nèi)部循環(huán)將跳過(guò)已經(jīng)匹配的文件。


文件名沖突應(yīng)該不是問(wèn)題,unset并且內(nèi)部break確保了這一點(diǎn)。不利的一面是,如果您在不同的子目錄中有多個(gè)文件要匹配。


如果速度是您所追求的,那么請(qǐng)使用通用腳本語(yǔ)言,例如python,perl和 friends


循環(huán)內(nèi)(極慢的)模式匹配的替代方法是grep


#!/usr/bin/env bash


files=file.list

source_dir=/path/to/source/files

destination_dir=/path/to/destination/files


while IFS= read -rd '' file; do

  cp -v "$file" "$destination_dir"

done < <(find "$source_dir" -type f -print0 | grep -Fzwf "$files")

-zfromgrep是一個(gè) GNU 擴(kuò)展。


echo如果您認(rèn)為輸出正確,請(qǐng)刪除。


查看完整回答
反對(duì) 回復(fù) 2022-11-24
  • 4 回答
  • 0 關(guān)注
  • 167 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)