재귀적 압축 아카이브 내에서 특정 크기의 파일 검색

재귀적 압축 아카이브 내에서 특정 크기의 파일 검색

여러 파일이 포함된 폴더가 있습니다. 이러한 파일은 .xml또는 .zip파일입니다. 이러한 .zip파일에는 .xml및/또는 .zip파일이 포함되어 있습니다. 여기에는 .zip또한 .xml또는 .zip등이 포함됩니다... 마침내 .xml파일을 찾을 때까지.

즉, 내 .xml파일을 찾기 전에 여러 "레벨"의 zip을 가질 수 있습니다(아래 예 참조).

내 요구 사항은 무엇을 감지하는 것입니다뿌리ZIP 파일에는 100Mb보다 큰 XML 파일이 하나 이상 포함되어 있습니다. 이러한 경우 ZIP 파일은 다른 디렉터리로 이동해야 합니다(예: ~/big-files). 또한 압축되지 않은 .xml파일이 100Mb보다 큰 경우 이 디렉터리로 이동해야 합니다.

예를 들어:

foo1.xml
foo2.xml
baz.xml [MORE THAN 100Mb]
one.zip
  +- foo.xml
  +- bar.xml [MORE THAN 100Mb]
  +- foo.xml
two.zip
  +- foo.xml
  +- zip-inside1.zip
  |   +- bar.xml [MORE THAN 100Mb]
  +- foo.xml
three.zip
  +- foo.xml
  +- zip-inside2.zip
  |   +- zip-inside3.zip
  |       +- foo.xml
  |       +- bar.xml [MORE THAN 100Mb]
  +- foo.xml
four.zip
  +- foo.xml
  +- zip-inside1.zip
      +- foo.xml

이 예에서는baz.xml,one.zip,two.zip그리고three.zip~/big-files100Mb보다 큰 XML 파일을 하나 이상 호스팅하므로 이동해야 합니다 .4.zip.

Bash 쉘에서 어떻게 이를 달성할 수 있습니까?

감사해요.

답변1

먼저 설치하세요AVFS, 아카이브 내부에 투명한 액세스를 제공하는 파일 시스템을 입력하고 명령을 실행합니다 mountavfs. 보다압축된 아카이브를 재귀적으로 grep하려면 어떻게 해야 합니까?배경.

그 다음에는 /path/to/archive.zip인식된 아카이브인 경우 ~/.avfs/path/to/archive.zip#아카이브의 내용을 포함하는 것으로 보이는 디렉터리가 있습니다.

has_large_file_rec인수로 전달된 zip 파일에서 큰 XML 파일을 찾고 포함된 모든 zip 파일에서 자신을 재귀적으로 호출하는 보조 스크립트를 작성합니다 . 이 스크립트는 내부에서 큰 XML 파일을 찾으면 일부 출력을 생성합니다. 하나의 큰 XML 파일을 찾으면 검색을 중단할 수도 있으므로 효율성을 위해 출력이 잘립니다.

#!/bin/sh
## auxiliary script has_large_file_rec
find "$1#" -name '*.zip' -type f -exec has_large_file_rec {} \; \
        -o -name '*.xml' -type f -size +1024k -print | head -n 1

최상위 수준에서 큰 파일을 찾으면 해당 파일을 큰 파일 디렉터리로 이동합니다.

find "~/.avfs$PWD" \
  -name '*.zip' -sh -c '
      a=$(has_large_file_rec "$0")
      if [ -n "$a" ]; then mv "$0" ~/big-files/; fi
                       ' {} \; -o \
  -name '*.xml' -type f -size +1024k -exec mv {} ~/big-files/ \;

답변2

을 사용하는 편도 perl.

의 내용 script.pl:

use warnings;
use strict;
use Archive::Extract;
use List::Util qw|first|;
use File::Copy qw|move|;
use File::Spec;
use File::Path qw|remove_tree|;

## Path to save 'xml' and 'zip' files.
my $big_files_dir = qq|$ENV{HOME}/big_files/|;

## Temp dir to extract files of 'zips'.
my $zips_path = qq|/tmp/zips$$/|;

## Size in bytes to check 'xml' files.
my $file_max_size_bytes = 100 * 1024 * 1024;

my (@zips_to_move, $orig_zip);

## Get files to process.
my @files = <*.xml *.zip>;                                                                                                                                                                                                                   

## From previous list, copy 'xml' files bigger than size limit.                                                                                                                                                                              
for my $file ( @files ) {                                                                                                                                                                                                                    
        if ( substr( $file, -4 ) eq q|.xml| and -s $file > $file_max_size_bytes ) {                                                                                                                                                          
                move $file, $big_files_dir;                                                                                                                                                                                                  
        }                                                                                                                                                                                                                                    
}                                                                                                                                                                                                                                            

## Process now 'zip' files. For each one remove temp dir to avoid mixing files                                                                                                                                                               
## from different 'zip' files.                                                                                                                                                                                                               
for ( grep { m/\.zip\Z/ } @files ) {                                                                                                                                                                                                         
        remove_tree $zips_path;                                                                                                                                                                                                              
        $orig_zip = $_;                                                                                                                                                                                                                      
        handle_zip_file( $orig_zip );                                                                                                                                                                                                        
}                                                                                                                                                                                                                                            

## Copy 'zip' files got until now.                                                                                                                                                                                                           
for my $zip_file ( @zips_to_move ) {                                                                                                                                                                                                         
        move $zip_file, $big_files_dir;                                                                                                                                                                                                      
}                                                                                                                                                                                                                                            

## Traverse recursively each 'zip file. It will look for 'zip' file in the                                                                                                                                                                   
## subtree and will extract all 'xml' files to a temp dir. Base case is when                                                                                                                                                                 
## a 'zip' file only contains 'xml' files, then I will read size of all 'xmls'                                                                                                                                                               
## and will copy the 'zip' if at least one of them if bigger than the size limit.                                                                                                                                                            
## To avoid an infinite loop searching into 'zip' files, I delete them just after                                                                                                                                                            
## the extraction of its content.                                                                                                                                                                                                            
sub handle_zip_file {                                                                                                                                                                                                                        
        my ($file) = @_;                                                                                                                                                                                                                     

        my $ae = Archive::Extract->new(                                                                                                                                                                                                      
                archive => $file,                                                                                                                                                                                                            
                type => q|zip|,                                                                                                                                                                                                              
        );                                                                                                                                                                                                                                   

        $ae->extract(
                to => $zips_path,
        );

        ## Don't check fails. I don't worry about them, ¿perhaps should I?
        unlink( File::Spec->catfile( 
                                (File::Spec->splitpath( $zips_path ))[1], 
                                (File::Spec->splitpath( $file ))[2],
                        )
        );

        my $zip = first { substr( $_, -4 ) eq q|.zip| } <$zips_path/*>;
        if ( ! $zip ) {
                for my $f ( <$zips_path/*.xml> ) {
                        if ( substr( $f, -4 ) eq q|.xml| and -s $f > $file_max_size_bytes ) {
                                push @zips_to_move, $orig_zip;
                                last;
                        }
                }
                return;
        }

        handle_zip_file( $zip );
}

몇 가지 문제:

  • xml임시 디렉토리에 복사하면 파일 의 하위 트리에 있는 동일한 이름의 파일을 zip덮어쓰게 됩니다.
  • 이 프로그램은 동일한 트리의 모든 zip 파일 내용을 추출한 다음 xml100MB보다 큰지 확인합니다. zip 파일을 추출할 때마다 확인하는 것이 더 빠릅니다. 개선될 수 있습니다.
  • 두 번 이상 처리된 zip 파일은 캐시하지 않습니다.
  • ~/big_files존재하고 쓰기 가능해야 합니다.
  • 스크립트는 인수를 허용하지 않습니다. zip및 파일 과 동일한 디렉터리에서 실행해야 합니다 xml.

이전 포인트에서 볼 수 있듯이 완벽하지는 않지만 테스트에서는 작동했습니다. 나는 그것이 당신에게 유용할 수 있기를 바랍니다.

다음과 같이 실행하세요:

perl script.pl

관련 정보