mv 파일을 정규식 대체를 통해 생성된 다른 경로로 복사

mv 파일을 정규식 대체를 통해 생성된 다른 경로로 복사

파일 이름을 기준으로 하위 디렉터리에 저장되는 파일로 가득 찬 디렉터리가 있습니다.

20d1/d325/52d1/20d1d32552d1a95249e62662fbdf924dd72c4027.jpg
ccaf/13cf/3199/ccaf13cf319930e80f5f2ad02525b93e1326c160.jpg
ec07/53bd/2355/ec0753bd2355fa8ec5cf5163e219c162cce3b03a.jpg
...

보시다시피 파일 이름의 처음 12자는 세 가지 수준의 하위 디렉터리를 만드는 데 사용됩니다. 불행하게도 각 디렉터리 이름에 4개의 문자가 선택되었으며 파일 수가 파일 시스템의 디렉터리당 항목 수인 32,000개의 디렉터리 제한을 초과했습니다. 따라서 다음과 같이 다시 작성해야 합니다.

20d/1d3/255/2d1/20d1d32552d1a95249e62662fbdf924dd72c4027.jpg
cca/f13/cf3/199/ccaf13cf319930e80f5f2ad02525b93e1326c160.jpg
ec0/753/bd2/355/ec0753bd2355fa8ec5cf5163e219c162cce3b03a.jpg
...

따라서 디렉터리당 4개가 아닌 3개의 문자가 사용됩니다. 파일이 많기 때문에 프로세스는 최대한 빨라야 합니다.

나는 다음과 같은 일을 해보았다 find.

find /path/to/files -mindepth 4 -type f -regextype posix-extended -regex \
".*/([0-9a-f]{4}/){3}(([0-9a-f]{3})([0-9a-f]{3})([0-9a-f]{3})([0-9a-f]{3})[0-9a-f]+\.\w+)" 

이렇게 하면 모든 파일이 제대로 인쇄되지만 다시 쓰기를 진행하는 방법을 잘 모르겠습니다. 재작성 프로세스 중에 정규식 캡처 그룹을 사용하여 경로 $3/$4/$5/$6/$2( find정규식에 대한 역참조) 를 다시 작성하고 싶습니다 . 하지만 find이와 같은 것은 지원되지 않는 것 같습니다.

find ... -exec cp {} /elsewhere/$3/$4/$5/$6/$2 ;

이 문제를 처리하는 가장 좋은 방법은 무엇입니까? 및 (저는 이것에 대해 경험이 많지 않습니다) sed의 일부 조합입니까 ? 작업을 수행하는 xargs대신 반복해야 합니까 ? find나는 조금 길을 잃었다.

답변1

파일을 복사하려면 find와 GNU tar의 조합을 사용하여 작업을 수행할 수 있습니다.

$ find -type f ... -print0 \
    | tar -c -f - --null --files-from - \
    | tar -C DEST_BASE -v -x -f - \
        --show-transformed \
        --transform 's,PATTERN,REPLACE,OPTIONS

(find는 모든 소스 파일 이름을 생성하고, 첫 번째 tar는 이를 파이프로 읽고, 두 번째 tar는 파일 이름/경로 변환을 수행합니다)

기본적으로 이 --transform옵션에는 기본 정규식이 필요하지만 xregexp-option을 사용할 수도 있습니다. 또 다른 유용한 정규식 옵션은 i대소문자를 구분하지 않는 일치입니다.

답변2

모바일의 경우 사용할 수 있습니다mmv:

$ mmv -n ';????????????*.jpg' '#2#3#4/#5#6#7/#8#9#10/#11#12#13/#14.jpg'
20d1/d325/52d1/20d1d32552d1a95249e62662fbdf924dd72c4027.jpg
    -> 20d/1d3/255/2d1/a95249e62662fbdf924dd72c4027.jpg
ccaf/13cf/3199/ccaf13cf319930e80f5f2ad02525b93e1326c160.jpg
    -> cca/f13/cf3/199/30e80f5f2ad02525b93e1326c160.jpg
ec07/53bd/2355/ec0753bd2355fa8ec5cf5163e219c162cce3b03a.jpg
    -> ec0/753/bd2/355/fa8ec5cf5163e219c162cce3b03a.jpg

(-n은 보고 및 테스트 전용입니다. 파일은 아직 실제로 이동되지 않았습니다.)

안타깝게도 mmv"누락된 디렉터리 생성" 옵션이 없으므로 실제로 이동하기 전에 이 작업을 수행해야 합니다.

$ mmv -n ';????????????*.jpg' '#2#3#4/#5#6#7/#8#9#10/#11#12#13/#14.jpg' \
    | sed 's,^.* -> \(.*/\)[^/]\+$,\1,' \
    | xargs mkdir -p

mmv정규 표현식이 아닌 쉘 와일드카드를 사용하십시오. 이 ;문자는 특별하며 소스 파일 기본 경로와 일치합니다. 역참조는 으로 표시됩니다 #n. 쉘 와일드카드는 확장 정규식만큼 강력하지 않기 때문에 ?파일 이름의 처음 12자를 일치시키기 위해 12개의 와일드카드를 사용했습니다.

답변3

파일이 많기 때문에 명령줄 길이 제한을 알고 있어야 합니다. 또한 성능상의 이유로 각 파일에 대해 새 프로세스를 시작하지 않는 것이 좋습니다.

파일을 복사하지 마십시오. 시간이 많이 걸리고 디스크 공간이 두 배로 늘어나며 복사본을 삭제하지 않고 원본 파일만 삭제하는 문제가 발생합니다. 파일 이동이 훨씬 더 안정적입니다.

이는 쉘 유틸리티를 사용하여 수행할 수 있지만 Perl, Python 또는 Ruby로 강력하고 효율적인 스크립트를 작성하는 것이 훨씬 쉽습니다. 인용 문제가 없거나 명령줄을 분할할 필요가 없습니다.

Perl(디렉토리 삭제 시 오류 검사 생략):

#!/usr/bin/env perl
use warnings;
for my $dir1 (<*>) {
    for my $dir2 (<$dir1/*>) {
        for my $dir3 (<$dir2/*>) {
            for my $file (<$dir3/*>) {
                $file =~ m:.*/((...)(...)(...)(...).*):;
                mkdir "$1";
                mkdir "$1/$2";
                mkdir "$1/$2/$3";
                mkdir "$1/$2/$3/$4";
                rename $file, "$1/$2/$3/$4/$file" or die "$file: $!";
            }
            rmdir $dir3;
        }
        rmdir $dir2;
    }
    rmdir $dir1;
}

관련 정보