파일 이름을 기준으로 하위 디렉터리에 저장되는 파일로 가득 찬 디렉터리가 있습니다.
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
옵션에는 기본 정규식이 필요하지만 x
regexp-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;
}