수천 개의 파일이 포함 된 큰 디렉토리를 효율적으로 삭제


159

수십만 개의 작은 파일로 인해 폴더가 다루기 어려워지는 문제가 있습니다.

수행 rm -rf하는 오류가 많은 파일이 있으며 대신 우리가해야 할 일은 다음과 같습니다.

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

이것은 작동하지만 매우 느리고 메모리 부족으로 끊임없이 실패합니다.

더 좋은 방법이 있습니까? 이상적으로는 내용을 신경 쓰지 않고 전체 디렉토리를 제거하고 싶습니다.


16
rm -rf *너무 많은 인수로 인해 폴더에서 실패했을 수 있습니다. 그러나 rm -rf folder/어쨌든 전체 디렉토리를 제거하려면 어떨까요?
sr_

4
수동으로 삭제하는 대신 폴더를 별도의 파티션에 놓고 간단히 && 형식 && 다시 마운트 해제하는 것이 좋습니다.
bbaja42

7
호기심에서-몇 개의 파일이 깨지는가 rm -rf?
jw013

7
"수천 개의 파일을 포함하는 큰 디렉토리를 효율적으로 삭제하십시오"와 같이 질문의 이름을보다 정확한 것으로 바꾸어야합니다. 디렉토리 그 내용 을 삭제하려면 정의에 따라 재귀가 필요합니다. 디렉토리 inode 자체를 수동으로 연결 해제하고 (아마 루트 권한이 필요할 수 있음) 파일 시스템을 마운트 해제하고 fsck이를 실행 하여 사용되지 않는 디스크 블록을 되 찾을 수는 있지만 그 방법은 위험 해 보이며 더 빠르지 않을 수 있습니다. 또한 파일 시스템 검사에는 파일 시스템 트리를 재귀 적으로 순회하는 것이 포함될 수 있습니다.
jw013

4
나는 한 후에는 ccache너무 큰 파일 트리를, 그리고 rm너무 오래 복용 (부진 전체 시스템을)했다, 파일 시스템 형식 떨어져 다른 모든 파일을 복사하는 것이 훨씬 더 빨리, 그리고 다시 복사합니다. 그 이후로 나는 거대한 작은 파일 트리에 전용 파일 시스템을 제공하므로 mkfs대신에 직접 사용할 수 있습니다 rm.
frostschutz 2016 년

답변:


211

rsync를 사용하는 것은 빠르고 간단합니다.

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/

@sarath의 대답은 또 다른 빠른 선택을 언급했습니다 : Perl! 벤치 마크가보다 빠릅니다 rsync -a --delete.

cd yourdirectory
perl -e 'for(<*>){((stat)[9]<(unlink))}'

출처 :

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux

4
감사합니다. 매우 유용합니다. 나는 항상 rsync를 사용하는데, 이것을 사용하여 삭제할 수 있을지 몰랐습니다. rm -rf보다 훨씬 빠름
John Powell

22
rsync일반보다 더 빠를 수 있습니다 rm그것은 올바른 순서로 삭제를 보장하기 때문에, 그래서 덜 btress 재 계산이 필요하다. 이 답변보기 serverfault.com/a/328305/105902
Marki555

7
사람이 재귀 적으로 내부의 모든 디렉토리와 파일을 삭제하는 펄 표현 수정할 수 directory_to_be_deleted를 ?
Abhinav

5
참고 : -P좀 더 많은 디스플레이를 위해 rsync에 옵션을 추가 하고 구문에주의하십시오. 후행 슬래시 필수입니다. 마지막으로, -n먼저 dry run 을 시작하는 옵션 으로 rsync 명령을 처음 시작할 수 있습니다 .
Drasill

1
-a동일 -rlptgoD하지만, 삭제 만 -rd필요하다
공원.

38

트위터의 누군가가 -delete대신 사용 을 제안했습니다.-exec rm -f{} \;

이것은 명령의 효율성을 향상 시켰지만 여전히 재귀를 사용하여 모든 것을 통과합니다.


11
이것은 비표준입니다. GNU find에는 -delete다른 것이 find있을 수 있습니다.
enzotib

13
-delete-exec rm안전과 효율성을 위해 가능한 경우 항상 선호합니다 .
jw013

6
GNU는 사실상의 표준입니다.
RonJohn

17

다음과 같은 것은 어떻습니까? find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

parameter의 인수를 변경하여 한 번에 삭제할 파일 수를 제한 할 수 있습니다 -n. 공백이있는 파일 이름도 포함됩니다.


2
-n 20xargs는 어쨌든 수용 가능한 인수 목록 크기로 제한해야하기 때문에 아마도 비트 가 필요하지 않을 것 입니다.
쓸모없는

네, 맞아요. 여기에서 메모입니다 man xargs: (...) max-chars characters per command line (...). The largest allowed value is system-dependent, and is calculated as the argument length limit for exec. 따라서 -n옵션은 xargs가 CLI 버퍼 크기를 결정할 수 없거나 실행 된 명령에 일부 제한이있는 경우입니다.
digital_infinity

12

영리한 속임수 :

rsync -a --delete empty/ your_folder/

슈퍼 CPU를 많이 사용하지만 실제로는 빠릅니다. https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html을 참조 하십시오


디렉토리 내용을 비효율적으로 읽으므로 빠르지 않습니다. 10 배 빠른 솔루션에 대한 설명은이 답변을 참조하십시오 serverfault.com/a/328305/105902
Marki555

2
@ Marki555 : 질문 편집에서에 대해 rsync -a --delete43 초 동안 60 초로보고 됩니다 lsdent. 10 배의 비율은 time ls -1 | wc -l vs입니다 time ./dentls bigfolder >out.txt( > filevs 때문에 부분적으로 공정한 비교입니다 wc -l).
Hastur

문제는이 NONE 저기 명령이 실제로 하지 않는다 삭제 원하는 탐색 작업을. 그들이주는 코드는? Marki555에 설명 된대로 작동하지 않습니다.
Svartalf

11

의견 중 하나를 확장하면, 당신이 생각하는 것을하고 있다고 생각하지 않습니다.

먼저 상황을 시뮬레이션하기 위해 엄청난 양의 파일을 만들었습니다.

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done

그런 다음 내가 실패 할 것으로 예상 한 것과 시도했던 것처럼 들었습니다.

$ rm -r foo/*
bash: /bin/rm: Argument list too long

그러나 이것은 효과 있습니다.

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

6
이것이 작동 한 유일한 솔루션입니다 rm -Rf bigdirectory. 여러 번 실행하십시오 . 수천만 개의 하위 디렉토리와 파일이있는 디렉토리가있었습니다. 난 실행할 수 없습니다 ls또는 find또는 rsync이 메모리가 부족하기 때문에, 그 디렉토리에. 이 명령 rm -Rf은 수십억 개의 파일 중 일부만 삭제하여 (메모리 부족) 여러 번 종료됩니다. 그러나 많은 재시도 끝에 마침내 작업이 완료되었습니다. 메모리 부족이 문제인 경우 유일한 해결책 인 것 같습니다.
erik

6

나는 테스트 할 기회가 있었다 -delete비교를 -exec rm \{\} \;나를 위해 -delete이 문제에 대한 답이었다.

를 사용 -delete하면 파일보다 최소 1,000 배 빠른 400,000 개 파일 폴더에서 파일을 삭제했습니다 rm.

'리눅스에서 많은 수의 파일을 삭제하는 방법'기사는 약 3 배 빠르지 만 내 테스트에서는 그 차이가 훨씬 극적이라고 제안합니다.


3
를 사용 find -exec하면 rm모든 파일에 대해 명령이 개별적으로 실행 되므로 속도가 너무 느립니다.
Marki555

5

-delete위 의 옵션 정보 : 나는 그것을 사용하여 임시 폴더에서 많은 (1M + est) 파일을 제거하고 실수로 밤에 정리하는 것을 잊었습니다. 디스크 / 파티션을 실수로 채웠으므로 find .명령 외에는 제거 할 수있는 것이 없습니다 . 처음에는 내가 사용하는 것이 느립니다.

find . -ls -exec rm {} \;

그러나 그것은 극단적 인 시간이 걸렸습니다. 약 15 분 후에 일부 파일을 제거하기 시작했지만 마침내 시작된 후 초당 10 개 이하로 제거되고 있다고 생각합니다. 그래서 나는 다음을 시도했다.

find . -delete

대신, 지금 당장 실행 시키도록하겠습니다. 다른 명령이 아닌 CPU에 과도하게 부담을 주지만 더 빠르게 실행되는 것으로 보입니다. 지금은 한 시간 동안 실행 중이며 드라이브에서 공간을 다시 확보하고 파티션이 점차 "감소"하지만 여전히 오랜 시간이 걸립니다. 나는 그것이 다른 것보다 1,000 배 빠르게 실행되는지 의심합니다. 모든 것에서와 같이, 나는 공간 대 시간의 절충점을 지적하고 싶었습니다. 여분의 CPU 대역폭이 있다면 (우리는) 후자를 실행하십시오. CPU가 실행 중입니다 ( uptime보고서).

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87

그리고로드 평균이 30.00 이상으로 바쁜 시스템에는 좋지 않지만 일반적으로 약간로드 된 시스템에 대해서는 2 시간 동안 괜찮습니다. 나는 시스템에서 대부분의 다른 것들을 점검했으며 여전히 반응이 있으므로 지금은 괜찮습니다.


사용 exec하려는 경우 거의 확실하게 사용 -ls하지 않으려 고하고 find . -type f -exec rm '{}' ++가 더 빠릅니다. rm에 한 번에 처리 할 수있는만큼 많은 인수를 제공하기 때문입니다.
xenoterracide

나는 당신이 계속해서 이것을 자신의 대답으로 편집해야한다고 생각합니다 ... 코멘트가 너무 길습니다. 또한 파일 시스템에 삭제가 상당히 비싼 것처럼 들립니다. 당신은 그것을 실행할 수 있습니다 find … -delete통해 nice또는 ionice, 그 도움이 될 수 있습니다. 따라서 일부 마운트 옵션을 충돌이 적은 설정으로 변경할 수 있습니다. (물론 파일 시스템에 무엇이 있는지에 따라 모든 것을 삭제하는 가장 빠른 방법은 종종 mkfs있습니다.)
derobert

3
로드 평균은 항상 CPU가 아니며 시간에 따른 차단 된 프로세스 수의 측정치 일뿐입니다. 프로세스는 디스크 I / O를 차단할 수 있으며 여기에서 발생할 수 있습니다.
Score_Under

또한로드 평균은 논리 CPU 수를 고려하지 않습니다. 따라서 1단일 코어 시스템의 loadavg 64는 64 코어 시스템의 loadavg와 동일하므로 각 CPU가 100 % 사용 중입니다.
Marki555


3

Btrfs 볼륨 사용을 고려하고 많은 파일이있는 디렉토리의 전체 볼륨을 삭제하십시오.

또는 FS 이미지 파일을 만든 다음 파일을 마운트 해제했다가 삭제하여 모든 것을 한 번에 빠르게 제거 할 수 있습니다.


2

GNU를 parallel설치 했다고 가정하면 다음을 사용했습니다.

parallel rm -rf dir/{} ::: `ls -f dir/`

그리고 그것은 충분히 빨랐다.


1

REALLY LARGE 디렉토리를 삭제하려면 이 사이트 에서 배운대로 다른 접근 방식 이 필요합니다. ionice를 사용해야합니다. -c3을 사용하면 시스템에 IO 시간이있는 경우에만 삭제가 수행되도록합니다. 시스템로드가 높지 않고 모든 것이 응답 상태로 유지됩니다 (찾기에 필요한 CPU 시간은 약 50 %로 매우 높음).

find <dir> -type f -exec ionice -c3 rm {} \;

5
+대신에 사용 \;하면 한 번에 rm에 더 많은 인수를 전달하고 더 적은 포크를 전달하므로 더 빠르게 만들 수 있습니다.
xenoterracide

1
ionice -c3 find <dir> -type f -delete
jtgd

0
ls -1 | xargs rm -rf 

기본 폴더 내에서 작동해야합니다


1
ls폴더의 파일 양으로 인해 작동하지 않습니다. 내가 사용했던 이유입니다 find하지만, 감사합니다.
Toby

4
@Toby : Try ls -f을 사용하면 정렬이 비활성화됩니다. 정렬하려면 전체 디렉토리를 메모리에로드하여 정렬해야합니다. 분류되지 않은 ls출력을 스트리밍 할 수 있어야합니다.
camh

1
줄 바꿈이 포함 된 파일 이름에는 작동하지 않습니다.
maxschlepzig

@camh 사실입니다. 그러나 정렬 된 순서로 파일을 제거하는 것은 정렬되지 않은 것보다 빠릅니다 (각 삭제 후 디렉토리의 btree를 다시 계산하기 때문에). serverfault.com/a/328305/105902
Marki555

이러한 파일에 대해 @maxschlepzig를 find . -print0 | xargs -0 rm사용하면 파일 이름 구분 기호로 NULL 문자가 사용됩니다.
Marki555

0

위의 이즈 카타 힌트 :

그러나 이것은 효과 있습니다.

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

이것은 거의 효과가 있었거나 효과가 있었지만 허가에 문제가있었습니다. 파일이 서버에 있었지만 여전히이 권한 문제의 원인을 이해하지 못합니다. 어쨌든, 터미널은 모든 파일에 대한 확인을 요청했습니다. 파일의 양은 약 20 000이므로 옵션이 아니 었습니다. "-r"뒤에 "-f"옵션을 추가 했으므로 전체 명령은 " rm -r -f foldername / "입니다. 그런 다음 제대로 작동하는 것 같습니다. 나는 터미널의 초보자이지만 이것이 괜찮은 것 같아요? 감사!


0

해당 파일을 얼마나 잘 제거해야하는지에 따라을 사용하는 것이 좋습니다 shred.

$ shred -zuv folder

디렉토리를 제거하고 싶지만 디렉토리를 제거하고 다시 만들 수없는 경우 디렉토리를 이동하고 즉시 다시 생성하는 것이 좋습니다.

mv folder folder_del
mkdir folder
rm -rf folder_del

하나의 inode 만 변경하면되기 때문에 더 빠르다. 기억하십시오 : 멀티 코어 컴퓨터에서이 추적을 병렬화 할 수는 없습니다. RAID에 의해 또는 당신이 가진 것에 의해 제한되는 디스크 액세스로 귀착됩니다.


1
shred 많은 최신 파일 시스템 에서는 작동하지 않습니다 .

0

수백만 개의 파일이 있고 위의 모든 솔루션으로 시스템에 스트레스가 생기면 다음과 같은 영감을 얻을 수 있습니다.

파일 nice_delete:

#!/bin/bash

MAX_LOAD=3
FILES=("$@")
BATCH=100

while [ ${#FILES[@]} -gt 0 ]; do
    DEL=("${FILES[@]:0:$BATCH}")
    ionice -c3 rm "${DEL[@]}"
    echo -n "#"
    FILES=("${FILES[@]:$BATCH}")
    while [[ $(cat /proc/loadavg | awk '{print int($1)}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done

이제 파일을 삭제하십시오.

find /path/to/folder -type f -exec ./nice_delete {} \+

Find는 getconf ARG_MAX수만 개의 파일을 배치 (참조 )로 만들어 전달합니다 nice_delete. 이렇게하면 과부하가 감지 될 때 휴면 상태가 될 수 있도록 더 작은 배치가 생성됩니다.


0

가능한 한 빨리 많은 파일을 제거하려면 ls -f1 /path/to/folder/with/many/files/ | xargs rm정상적으로 작동하지만 시스템이 IO 문제가되고 삭제 작업 중에 응용 프로그램이 멈출 수 있으므로 프로덕션 시스템에서 실행하지 않는 것이 좋습니다.

이 스크립트는 많은 파일에 적합하며 시스템의 ioload에 영향을 미치지 않습니다.

#!/bin/bash

# Path to folder with many files
FOLDER="/path/to/folder/with/many/files"

# Temporary file to store file names
FILE_FILENAMES="/tmp/filenames"

if [ -z "$FOLDER" ]; then
    echo "Prevented you from deleting everything! Correct your FOLDER variable!"
    exit 1
fi

while true; do
    FILES=$(ls -f1 $FOLDER | wc -l)
    if [ "$FILES" -gt 10000 ]; then
        printf "[%s] %s files found. going on with removing\n" "$(date)" "$FILES"
        # Create new list of files
        ls -f1 $FOLDER | head -n 5002 | tail -n 5000 > "$FILE_FILENAMES"

        if [ -s $FILE_FILENAMES ]; then
            while read FILE; do
                rm "$FOLDER/$FILE"
                sleep 0.005
            done < "$FILE_FILENAMES"
        fi
    else
        printf "[%s] script has finished, almost all files have been deleted" "$(date)"
        break
    fi
    sleep 5
done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.