Xóa hiệu quả thư mục lớn chứa hàng ngàn tệp


162

Chúng tôi gặp sự cố với một thư mục trở nên khó sử dụng với hàng trăm ngàn tệp nhỏ.

Có rất nhiều tệp thực hiện rm -rftrả về một lỗi và thay vào đó, những gì chúng ta cần làm là một cái gì đó như:

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

Điều này hoạt động nhưng rất chậm và liên tục thất bại do hết bộ nhớ.

Có cách nào tốt hơn để làm điều này? Lý tưởng nhất là tôi muốn xóa toàn bộ thư mục mà không quan tâm đến nội dung bên trong nó.


16
rm -rf *trong thư mục có thể thất bại vì quá nhiều đối số; Nhưng rm -rf folder/nếu bạn muốn loại bỏ toàn bộ thư mục thì sao?
sr_

4
Thay vì xóa thủ công, tôi khuyên bạn nên có thư mục trên một phân vùng riêng và chỉ cần ngắt kết nối && định dạng && remount.
bbaja42

7
Vì tò mò - cần bao nhiêu tập tin để phá vỡ rm -rf?
jw013

7
Có lẽ bạn nên đổi tên câu hỏi thành một cái gì đó chính xác hơn, như "Xóa hiệu quả thư mục lớn chứa hàng ngàn tệp." Để xóa một thư mục nội dung của nó, đệ quy là cần thiết theo định nghĩa. Bạn có thể tự hủy liên kết thư mục inode (có thể yêu cầu quyền root), ngắt kết nối hệ thống tệp và chạy fscktrên nó để lấy lại các khối đĩa không sử dụng, nhưng cách tiếp cận đó có vẻ nguy hiểm và có thể không nhanh hơn. Ngoài ra, kiểm tra hệ thống tệp có thể liên quan đến việc duyệt qua đệ quy cây dù sao đi nữa.
jw013

4
Khi tôi có một ccachecây tệp rất lớn và rmmất nhiều thời gian (và làm cho toàn bộ hệ thống chậm chạp), việc sao chép tất cả các tệp khác khỏi hệ thống tệp, định dạng và sao chép chúng trở lại nhanh hơn đáng kể. Kể từ đó, tôi cung cấp cho các cây tệp lớn như vậy hệ thống tệp chuyên dụng của riêng họ, vì vậy bạn có thể mkfstrực tiếp thay thế rm.
frostschutz

Câu trả lời:


213

Sử dụng rsync là đáng ngạc nhiên nhanh chóng và đơn giản.

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

Câu trả lời của @ sarath đã đề cập đến một lựa chọn nhanh khác: Perl! Điểm chuẩn của nó là nhanh hơn rsync -a --delete.

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

Nguồn:

  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
Cảm ơn, rất hữu ích. Tôi sử dụng rsync mọi lúc, tôi không biết bạn có thể sử dụng nó để xóa như thế này. Nhanh hơn rất nhiều so với rm -rf
John Powell

22
rsynccó thể nhanh hơn đơn giản rm, vì nó đảm bảo xóa theo đúng thứ tự, do đó cần tính toán lại btress ít hơn. Xem câu trả lời này serverfault.com/a/328305/105902
Marki555

7
Bất cứ ai cũng có thể sửa đổi biểu thức perl để xóa đệ quy tất cả các thư mục và tệp trong một thư mục_to_be_delatted ?
Abhinav

5
Lưu ý: thêm -Ptùy chọn vào rsync để hiển thị thêm, ngoài ra, hãy cẩn thận về cú pháp, dấu gạch chéo bắt buộc. Cuối cùng, bạn có thể bắt đầu lệnh rsync lần đầu tiên với -ntùy chọn đầu tiên để khởi chạy chạy khô .
Drasill

1
-abằng -rlptgoD, nhưng chỉ để xóa -rdlà cần thiết
Koen.

38

Ai đó trên Twitter đề nghị sử dụng -deletethay vì-exec rm -f{} \;

Điều này đã cải thiện hiệu quả của lệnh, nó vẫn sử dụng đệ quy để đi qua tất cả mọi thứ mặc dù.


11
Đây là không chuẩn. GNU find-delete, và findcó thể khác .
enzotib

13
-deletenên luôn luôn được ưu tiên -exec rmkhi có sẵn, vì lý do an toàn và hiệu quả.
jw013

6
GNU là tiêu chuẩn thực tế .
RonJohn

17

Điều gì về một cái gì đó như: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Bạn có thể giới hạn số lượng tệp cần xóa cùng một lúc bằng cách thay đổi đối số cho tham số -n. Tên tập tin với khoảng trống cũng được bao gồm.


2
Bạn có thể không cần -n 20bit, vì xargs nên tự giới hạn ở kích thước danh sách đối số được chấp nhận.
Vô dụng

Vâng, bạn đúng. Đây là một lưu ý từ 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. Vì vậy, -ntùy chọn dành cho các trường hợp như vậy trong đó xargs không thể xác định kích thước bộ đệm CLI hoặc nếu lệnh được thực thi có một số giới hạn.
digital_infinity

12

Một mẹo thông minh:

rsync -a --delete empty/ your_folder/

Đó là siêu CPU chuyên sâu, nhưng thực sự rất nhanh. Xem https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html


Nó không quá nhanh, bởi vì nó đọc nội dung thư mục một cách hiệu quả. Xem câu trả lời này để biết giải pháp nhanh hơn và giải thích serverfault.com/a/328305/105902
Marki555

2
@ Marki555: trong phần Chỉnh sửa câu hỏi, nó được báo cáo 60 giây rsync -a --deleteso với 43 cho lsdent. Tỷ lệ 10 x là time ls -1 | wc -l so với vs time ./dentls bigfolder >out.txt(đó là so sánh công bằng một phần vì > fileso với wc -l).
Hastur

Vấn đề có là NONE của các lệnh trên có thực sự DO hoạt động traversal mong muốn để xóa. Mã họ đưa ra? KHÔNG LÀM VIỆC như được mô tả bởi Marki555.
Svartalf

11

Mở rộng trên một trong những ý kiến, tôi không nghĩ bạn đang làm những gì bạn nghĩ bạn đang làm.

Đầu tiên tôi tạo một số lượng lớn tệp để mô phỏng tình huống của bạn:

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

Sau đó, tôi đã thử những gì tôi dự đoán sẽ thất bại và những gì nghe giống như bạn đang làm trong câu hỏi:

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

Nhưng điều này không hoạt động:

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

6
Đây là giải pháp duy nhất có hiệu quả: Chạy rm -Rf bigdirectorynhiều lần. Tôi đã có một thư mục với hàng ngàn triệu thư mục con và tệp. Tôi thậm chí không thể chạy lshoặc findhoặc rsynctrong thư mục đó, bởi vì nó chạy ra khỏi bộ nhớ. Lệnh rm -Rfthoát nhiều lần (hết bộ nhớ) chỉ xóa một phần của hàng tỷ tệp. Nhưng sau nhiều lần thử lại, cuối cùng nó cũng làm được. Có vẻ là giải pháp duy nhất nếu hết bộ nhớ là vấn đề.
erik

6

Tôi đã có cơ hội để kiểm tra -deleteso với -exec rm \{\} \;và đối với tôi -deletelà câu trả lời cho vấn đề này.

Sử dụng -deleteđã xóa các tệp trong một thư mục gồm 400.000 tệp nhanh hơn ít nhất 1.000 lần so với rm.

Bài viết 'Cách xóa số lượng lớn tệp trong linux' cho thấy nó nhanh hơn khoảng ba lần, nhưng trong thử nghiệm của tôi, sự khác biệt còn ấn tượng hơn nhiều.


3
Việc sử dụng find -execthực thi rmlệnh cho mỗi tệp riêng biệt, đó là lý do tại sao nó quá chậm.
Marki555

5

Về -deletetùy chọn ở trên: Tôi đang sử dụng nó để xóa một số lượng lớn tệp (1M + est) trong thư mục tạm thời mà tôi đã tạo và vô tình quên dọn dẹp hàng đêm. Tôi vô tình điền vào đĩa / phân vùng của mình và không có gì khác có thể loại bỏ chúng ngoài find .lệnh. Nó rất chậm, lúc đầu tôi đang sử dụng:

find . -ls -exec rm {} \;

Nhưng điều đó đã chiếm một lượng thời gian EXTREME. Nó bắt đầu sau khoảng 15 phút để xóa một số tệp, nhưng tôi đoán là nó đã xóa ít hơn 10 hoặc mỗi giây sau khi cuối cùng nó bắt đầu. Vì vậy, tôi đã thử:

find . -delete

thay vào đó, và tôi đang để nó chạy ngay bây giờ. Nó dường như đang chạy nhanh hơn, mặc dù nó cực kỳ đánh thuế vào CPU mà lệnh khác không có. Bây giờ nó đã chạy được một giờ và tôi nghĩ rằng tôi đang lấy lại không gian trên ổ đĩa của mình và phân vùng dần dần "giảm béo" nhưng nó vẫn mất một thời gian rất dài. Tôi thực sự nghi ngờ rằng nó chạy nhanh hơn 1.000 lần so với cái khác. Như trong tất cả mọi thứ, tôi chỉ muốn chỉ ra sự đánh đổi trong không gian so với thời gian. Nếu bạn có băng thông CPU để dự phòng (chúng tôi làm) thì hãy chạy cái sau. Nó chạy CPU của tôi ( uptimebáo cáo):

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

Và tôi đã thấy mức trung bình tải vượt quá 30,00, điều này không tốt cho một hệ thống bận rộn, nhưng đối với hệ thống của chúng tôi thường được tải nhẹ, sẽ ổn trong vài giờ. Tôi đã kiểm tra hầu hết những thứ khác trên hệ thống và chúng vẫn phản hồi nên hiện tại chúng tôi vẫn ổn.


nếu bạn sẽ sử dụng, execbạn gần như chắc chắn không muốn sử dụng -lsvà làm find . -type f -exec rm '{}' ++ nhanh hơn bởi vì nó sẽ đưa ra càng nhiều đối số cho rm vì nó có thể xử lý cùng một lúc.
xenoterracide

Tôi nghĩ bạn nên tiếp tục và chỉnh sửa nó thành câu trả lời của riêng mình. Nó thực sự quá dài cho một nhận xét. Ngoài ra, có vẻ như hệ thống tập tin của bạn có xóa khá tốn kém, tò mò đó là cái gì? Bạn có thể chạy nó find … -deletethông qua nicehoặc ionice, điều đó có thể giúp đỡ. Vì vậy, có thể thay đổi một số tùy chọn gắn kết thành cài đặt ít an toàn hơn. (Và, tất nhiên, tùy thuộc vào những gì khác trên hệ thống tệp, cách nhanh nhất để xóa mọi thứ thường là mkfs.)
derobert

3
Tải trung bình không phải lúc nào cũng là CPU, nó chỉ là thước đo số lượng tiến trình bị chặn theo thời gian. Các quy trình có thể chặn trên I / O đĩa, có khả năng những gì đang xảy ra ở đây.
Điểm_Under

Cũng lưu ý rằng tải trung bình không chiếm số lượng CPU logic. Vì vậy, loadavg 1cho máy lõi đơn giống như loadavg 64trên hệ thống 64 lõi - nghĩa là mỗi CPU bận 100% thời gian.
Marki555

3

Có một số phương thức có thể được sử dụng để xóa số lượng lớn tệp trong linux ,. Bạn có thể sử dụng tùy chọn find with xóa, nhanh hơn tùy chọn exec. Sau đó, bạn có thể sử dụng perl unlink, thậm chí rsync. Cách xóa số lượng lớn tệp trong linux


3

Xem xét sử dụng âm lượng Btrfs và chỉ cần xóa toàn bộ âm lượng cho một thư mục như vậy với số lượng lớn tệp.

Ngoài ra, bạn có thể tạo một tệp hình ảnh FS sau đó ngắt kết nối và xóa tệp của nó để xóa mọi thứ cùng một lúc thực sự nhanh chóng.


2

Giả sử đã parallelcài đặt GNU , tôi đã sử dụng điều này:

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

và nó đã đủ nhanh.


1

Xóa các thư mục THỰC SỰ LỚN cần một cách tiếp cận khác, như tôi đã học được từ trang web này - bạn sẽ cần sử dụng ionice. Nó đảm bảo (với -c3) rằng việc xóa sẽ chỉ được thực hiện khi hệ thống có thời gian IO cho nó. Tải hệ thống của bạn sẽ không tăng lên cao và mọi thứ vẫn phản hồi (mặc dù thời gian tìm CPU của tôi khá cao khoảng 50%).

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

5
sử dụng +thay vì \;sẽ làm điều này nhanh hơn vì nó chuyển nhiều đối số hơn đến rm cùng một lúc, ít
giả mạo

1
Tại sao không ionice -c3 find <dir> -type f -delete
jtgd

0
ls -1 | xargs rm -rf 

nên làm việc trong thư mục chính


1
lssẽ không hoạt động vì số lượng tệp trong thư mục. Đây là lý do tại sao tôi phải sử dụng find, cảm ơn mặc dù.
Toby

4
@Toby: Hãy thử ls -f, vô hiệu hóa sắp xếp. Sắp xếp yêu cầu toàn bộ thư mục được tải vào bộ nhớ để được sắp xếp. Một loại chưa được sắp xếp lscó thể truyền phát đầu ra của nó.
camh

1
Không hoạt động trên tên tệp có chứa dòng mới.
maxschlepzig

@camh đó là sự thật. Nhưng việc xóa các tệp theo thứ tự được sắp xếp nhanh hơn trong không sắp xếp (vì tính toán lại btree của thư mục sau mỗi lần xóa). Xem câu trả lời này để biết ví dụ serverfault.com/a/328305/105902
Marki555

@maxschlepzig cho các tệp như vậy bạn có thể sử dụng find . -print0 | xargs -0 rm, tệp này sẽ sử dụng char NULL làm dấu tách tên tệp.
Marki555

0

Đối với gợi ý của Izkata ở trên:

Nhưng điều này không hoạt động:

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

Điều này gần như đã làm việc - hoặc sẽ có hiệu quả - nhưng tôi đã có một số vấn đề trong sự cho phép; các tệp đã ở trên một máy chủ, nhưng tôi vẫn không hiểu vấn đề cấp phép này đến từ đâu. Dù sao, Terminal yêu cầu xác nhận trên mỗi tập tin. Số lượng tệp khoảng 20 000, vì vậy đây không phải là một tùy chọn. Sau "-r" Tôi đã thêm tùy chọn "-f", vì vậy toàn bộ lệnh là " rm -r -f Foldername / ". Sau đó, nó dường như làm việc tốt. Tôi là người mới với Terminal, nhưng tôi đoán điều này không sao, phải không? Cảm ơn!


0

Tùy thuộc vào mức độ bạn cần loại bỏ các tệp đó, tôi khuyên bạn nên sử dụng shred.

$ shred -zuv folder

nếu bạn muốn xóa thư mục, nhưng bạn không thể xóa nó và tạo lại nó, tôi khuyên bạn nên di chuyển nó và tạo lại nó ngay lập tức.

mv folder folder_del
mkdir folder
rm -rf folder_del

Điều này nhanh hơn, tin hay không, vì chỉ có một nút phải được thay đổi. Hãy nhớ rằng: Bạn không thể thực sự song song hóa thị hiếu này trên máy tính đa lõi. Nó đi xuống truy cập đĩa, bị giới hạn bởi RAID hoặc những gì có bạn.


1
shred sẽ không hoạt động với nhiều hệ thống tập tin hiện đại.

0

Nếu bạn có hàng triệu tệp và mọi giải pháp ở trên khiến hệ thống của bạn bị căng thẳng, bạn có thể thử cảm hứng này:

Tập tin 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

Và bây giờ xóa các tập tin:

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

Tìm sẽ tạo các lô (xem getconf ARG_MAX) của hàng chục ngàn tệp và chuyển nó tới nice_delete. Điều này sẽ tạo ra các lô thậm chí nhỏ hơn để cho phép ngủ khi phát hiện quá tải.


0

Nếu bạn chỉ muốn loại bỏ nhiều tệp càng sớm càng tốt ls -f1 /path/to/folder/with/many/files/ | xargs rmcó thể hoạt động tốt, nhưng tốt hơn đừng chạy nó trên các hệ thống sản xuất vì hệ thống của bạn có thể trở thành sự cố IO và các ứng dụng có thể bị kẹt trong quá trình xóa.

Kịch bản này hoạt động tốt cho nhiều tệp và không ảnh hưởng đến ioload của hệ thống.

#!/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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.