Hapus direktori besar yang berisi ribuan file secara efisien

162

Kami memiliki masalah dengan folder menjadi berat dengan ratusan ribu file kecil.

Ada begitu banyak file yang melakukan rm -rfpengembalian kesalahan dan sebaliknya yang perlu kita lakukan adalah sesuatu seperti:

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

Ini berfungsi tetapi sangat lambat dan terus-menerus gagal kehabisan memori.

Apakah ada cara yang lebih baik untuk melakukan ini? Idealnya saya ingin menghapus seluruh direktori tanpa mempedulikan konten di dalamnya.

Toby
sumber
17
rm -rf *dalam folder mungkin gagal karena terlalu banyak argumen; tetapi bagaimana rm -rf folder/jika Anda ingin menghapus seluruh direktori?
sr_
4
Daripada menghapusnya secara manual, saya sarankan memiliki folder pada partisi yang terpisah dan cukup meng-unmount && format && remount.
bbaja42
7
Hanya ingin tahu - berapa banyak file yang dibutuhkan untuk memecahnya rm -rf?
jw013
7
Anda mungkin harus mengubah nama pertanyaan menjadi sesuatu yang lebih akurat, seperti "Hapus direktori besar yang berisi ribuan file secara efisien." Untuk menghapus direktori dan isinya, rekursi diperlukan menurut definisi. Anda dapat memutuskan tautan secara manual hanya inode direktori itu sendiri (mungkin memerlukan hak akses root), unmount sistem file, dan jalankan fsckdi atasnya untuk merebut kembali blok-blok disk yang tidak digunakan, tetapi pendekatan itu tampaknya berisiko dan mungkin tidak lebih cepat. Selain itu, pemeriksaan sistem file mungkin melibatkan melintasi pohon sistem file secara rekursif.
jw013
4
Setelah saya memiliki ccachepohon file yang sangat besar, dan rmbutuh waktu lama (dan membuat seluruh sistem lamban), itu jauh lebih cepat untuk menyalin semua file lain dari sistem file, memformat, dan menyalinnya kembali. Sejak saat itu saya memberikan pohon file besar kecil seperti sistem file khusus mereka sendiri, sehingga Anda dapat mkfslangsung, bukan rm.
frostschutz

Jawaban:

213

Menggunakan rsync sangat cepat dan sederhana.

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

Jawaban @ sarath menyebutkan pilihan cepat lain: Perl! Tolok ukurnya lebih cepat dari rsync -a --delete.

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

Sumber:

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/which-is-the-the-tercepat-method-to-delete-files-in-linux
stevendaniel
sumber
4
Terima kasih, sangat berguna. Saya menggunakan rsync sepanjang waktu, saya tidak tahu Anda bisa menggunakannya untuk menghapus seperti ini. Jauh lebih cepat daripada rm -rf
John Powell
22
rsyncbisa lebih cepat daripada biasa rm, karena itu menjamin penghapusan dalam urutan yang benar, sehingga perhitungan btress lebih sedikit diperlukan. Lihat jawaban ini serverfault.com/a/328305/105902
Marki555
7
Adakah yang bisa memodifikasi ekspresi perl untuk menghapus semua direktori dan file di dalam direktori_to_be_deleted secara rekursif ?
Abhinav
5
Catatan: tambahkan -Popsi ke rsync untuk beberapa tampilan lagi, juga, berhati-hatilah dengan sintaksisnya, garis miring tambahan wajib ada. Akhirnya, Anda dapat memulai perintah rsync pertama kali dengan -nopsi pertama untuk meluncurkan menjalankan kering .
Drasill
1
-asama -rlptgoD, tetapi untuk penghapusan hanya -rddiperlukan
Koen.
38

Seseorang di Twitter menyarankan menggunakan -deletebukannya-exec rm -f{} \;

Ini telah meningkatkan efisiensi perintah, masih menggunakan rekursi untuk melalui semuanya.

Toby
sumber
11
Ini bukan standar. GNU findmiliki -delete, dan lainnya findmungkin.
enzotib
13
-deleteharus selalu disukai -exec rmbila tersedia, untuk alasan keamanan dan efisiensi.
jw013
6
GNU adalah standar de facto .
RonJohn
17

Bagaimana dengan sesuatu seperti: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Anda dapat membatasi jumlah file untuk dihapus sekaligus dengan mengubah argumen untuk parameter -n. Nama file dengan kosong juga disertakan.

digital_infinity
sumber
2
Anda mungkin tidak memerlukannya -n 20, karena xargs harus membatasi dirinya sendiri ke ukuran daftar argumen yang dapat diterima.
berguna
Ya kamu benar. Berikut adalah catatan dari 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. Jadi -nopsi untuk kasus-kasus seperti itu di mana xargs tidak dapat menentukan ukuran buffer CLI atau jika perintah yang dijalankan memiliki beberapa batasan.
digital_infinity
12

Trik yang cerdas:

rsync -a --delete empty/ your_folder/

Ini super CPU intensif, tetapi sangat cepat. Lihat https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html

MZAweb
sumber
Ini tidak begitu cepat, karena membaca isi direktori secara tidak efisien. Lihat jawaban ini untuk solusi 10x lebih cepat dan penjelasan serverfault.com/a/328305/105902
Marki555
2
@ Marki555: dalam Edit pertanyaan dilaporkan 60 detik untuk rsync -a --deletevs 43 untuk lsdent. Rasio 10x adalah untuk time ls -1 | wc -l vs time ./dentls bigfolder >out.txt(itu adalah perbandingan yang adil sebagian karena > filevs wc -l).
Hastur
Masalahnya adalah bahwa NONE dari perintah di sana benar-benar MELAKUKAN operasi traversal yang diinginkan untuk dihapus. Kode yang mereka berikan? TIDAK BEKERJA seperti yang dijelaskan oleh Marki555.
Svartalf
11

Memperluas salah satu komentar, saya tidak berpikir Anda melakukan apa yang Anda pikir Anda lakukan.

Pertama saya membuat sejumlah besar file, untuk mensimulasikan situasi Anda:

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

Kemudian saya mencoba apa yang saya harapkan gagal, dan apa yang Anda lakukan dalam pertanyaan:

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

Tapi ini tidak bekerja:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory
Izkata
sumber
6
Ini adalah satu-satunya solusi yang berhasil: Jalankan rm -Rf bigdirectorybeberapa kali. Saya memiliki direktori dengan ribuan jutaan subdirektori dan file. Saya bahkan tidak bisa menjalankan lsatau findatau rsyncdalam direktori itu, karena kehabisan memori. Perintah rm -Rfberhenti berkali-kali (kehabisan memori) hanya menghapus bagian dari miliaran file. Tetapi setelah banyak percobaan akhirnya berhasil. Tampaknya menjadi satu-satunya solusi jika kehabisan memori adalah masalahnya.
erik
6

Saya memiliki kesempatan untuk menguji -deletedibandingkan dengan -exec rm \{\} \;dan bagi saya -deleteadalah jawaban untuk masalah ini.

Menggunakan -deletemenghapus file dalam folder 400.000 file setidaknya 1.000 kali lebih cepat daripada rm.

Artikel 'Cara menghapus banyak file di linux' menunjukkan bahwa ini sekitar tiga kali lebih cepat, tetapi dalam pengujian saya perbedaannya jauh lebih dramatis.

pengguna2365090
sumber
3
Menggunakan find -execmengeksekusi rmperintah untuk setiap file secara terpisah, itu sebabnya sangat lambat.
Marki555
5

Tentang -deleteopsi di atas: Saya menggunakannya untuk menghapus sejumlah besar file (1M + est) di folder temp yang saya buat dan secara tidak sengaja lupa untuk membersihkannya setiap malam. Saya mengisi disk / partisi saya secara tidak sengaja, dan tidak ada yang bisa menghapusnya kecuali find .perintahnya. Ini lambat, pada awalnya saya menggunakan:

find . -ls -exec rm {} \;

Tapi itu membutuhkan waktu yang EXTREME. Itu dimulai setelah sekitar 15 menit untuk menghapus beberapa file, tetapi tebakan saya adalah itu menghapus kurang dari 10 atau lebih per detik setelah akhirnya dimulai. Jadi, saya mencoba:

find . -delete

sebagai gantinya, dan saya membiarkannya berjalan sekarang. Tampaknya berjalan lebih cepat, meskipun itu sangat berat pada CPU yang perintah lainnya tidak. Sudah berjalan selama satu jam sekarang dan saya pikir saya mendapatkan ruang kembali pada drive saya dan partisi secara bertahap "melangsingkan" tetapi masih membutuhkan waktu yang sangat lama. Saya ragu itu berjalan 1.000 kali lebih cepat dari yang lain. Seperti dalam semua hal, saya hanya ingin menunjukkan pengorbanan dalam ruang vs waktu. Jika Anda memiliki bandwidth CPU untuk cadangan (kami lakukan) kemudian jalankan yang terakhir. Ini membuat CPU saya berjalan ( uptimelaporan):

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

Dan saya telah melihat rata-rata beban lebih dari 30,00 yang tidak baik untuk sistem yang sibuk, tetapi untuk kita yang biasanya dimuat dengan ringan, tidak apa-apa selama beberapa jam. Saya telah memeriksa sebagian besar hal lain di sistem dan masih responsif sehingga kami OK untuk saat ini.

Scotty
sumber
jika Anda akan menggunakan execAnda hampir pasti ingin tidak menggunakan -lsdan melakukan find . -type f -exec rm '{}' ++ lebih cepat karena itu akan memberikan banyak argumen kepada rm karena dapat menangani sekaligus.
xenoterracide
Saya pikir Anda harus melanjutkan dan mengedit ini menjadi jawaban sendiri ... itu terlalu lama untuk komentar. Juga, sepertinya sistem file Anda memiliki penghapusan yang cukup mahal, penasaran yang mana? Anda dapat menjalankannya find … -deletemelalui niceatau ionice, yang dapat membantu. Jadi mungkin mengubah beberapa opsi pemasangan ke pengaturan yang kurang aman untuk kecelakaan. (Dan, tentu saja, tergantung pada apa lagi yang ada di sistem file, cara tercepat untuk menghapus semuanya sering kali mkfs.)
derobert
3
Rata-rata beban tidak selalu CPU, itu hanya ukuran dari jumlah proses yang diblokir dari waktu ke waktu. Proses dapat memblokir pada disk I / O, yang mungkin terjadi di sini.
Score_Under
Perhatikan juga bahwa rata-rata memuat tidak memperhitungkan jumlah CPU logis. Jadi loadavg 1untuk mesin single-core sama dengan loadavg 64pada sistem 64-core - artinya setiap CPU sibuk 100% waktu.
Marki555
3

Ada beberapa metode yang dapat digunakan untuk menghapus sejumlah besar file di linux,. Anda dapat menggunakan find dengan opsi hapus, yang lebih cepat dari opsi exec. Kemudian Anda dapat menggunakan perl unlink, kemudian bahkan rsync. Cara menghapus sejumlah besar file di linux

sarath
sumber
3

Pertimbangkan untuk menggunakan volume Btrfs dan hapus seluruh volume untuk direktori semacam itu dengan banyak file.

Atau Anda dapat membuat file gambar FS kemudian unmount dan menghapus file untuk menghapus semuanya sekaligus dengan sangat cepat.

Sergei
sumber
2

Dengan asumsi telah parallelmenginstal GNU , saya telah menggunakan ini:

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

dan itu cukup cepat.

Nacho
sumber
1

Menghapus direktori yang BENAR-BENAR BESAR membutuhkan pendekatan yang berbeda, seperti yang saya pelajari dari situs ini - Anda harus menggunakan ionice. Ini memastikan (dengan -c3) bahwa penghapusan hanya akan dilakukan ketika sistem memiliki IO-waktu untuk itu. Sistem Anda memuat tidak akan naik ke tinggi dan semuanya tetap responsif (meskipun waktu CPU saya untuk menemukan cukup tinggi sekitar 50%).

find <dir> -type f -exec ionice -c3 rm {} \;
gamma
sumber
5
menggunakan +bukannya \;akan membuat ini lebih cepat karena melewati lebih banyak argumen untuk rm sekaligus, kurang forking
xenoterracide
1
Kenapa tidak ionice -c3 find <dir> -type f -delete
jtgd
0
ls -1 | xargs rm -rf 

harus berfungsi di dalam folder utama

PsyStyle
sumber
1
lstidak akan berfungsi karena jumlah file di folder. Ini sebabnya saya harus menggunakan find, terima kasih.
Toby
4
@Toby: Coba ls -f, yang menonaktifkan penyortiran. Penyortiran mengharuskan seluruh direktori dimuat ke dalam memori untuk disortir. Yang tidak disortir lsharus dapat mengalirkan outputnya.
camh
1
Tidak berfungsi pada nama file yang mengandung baris baru.
maxschlepzig
@ Camh itu benar. Tetapi menghapus file dalam urutan diurutkan lebih cepat daripada tidak disortir (karena menghitung ulang btree direktori setelah setiap penghapusan). Lihat jawaban ini untuk contoh serverfault.com/a/328305/105902
Marki555
@maxschlepzig untuk file seperti itu dapat Anda gunakan find . -print0 | xargs -0 rm, yang akan menggunakan char NULL sebagai pemisah nama file.
Marki555
0

Untuk petunjuk Izkata di atas:

Tapi ini tidak bekerja:

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

Ini hampir berhasil - atau mungkin berhasil - tetapi saya memiliki beberapa masalah dalam izin; file ada di server, tetapi saya masih tidak mengerti dari mana masalah izin ini berasal. Bagaimanapun, Terminal meminta konfirmasi pada setiap file. Jumlah file sekitar 20.000, jadi ini bukan pilihan. Setelah "-r" saya menambahkan opsi "-f", jadi seluruh perintahnya adalah " rm -r -f foldername / ". Kemudian itu tampaknya bekerja dengan baik. Saya seorang pemula dengan Terminal, tapi saya kira ini tidak apa-apa, kan? Terima kasih!

pengguna41527
sumber
0

Tergantung pada seberapa baik Anda perlu menyingkirkan file-file itu, saya sarankan menggunakan shred.

$ shred -zuv folder

jika Anda ingin membersihkan direktori, tetapi Anda tidak dapat menghapusnya dan membuatnya kembali, saya sarankan memindahkannya dan membuatnya kembali secara instan.

mv folder folder_del
mkdir folder
rm -rf folder_del

ini lebih cepat, percaya atau tidak, karena hanya satu inode yang harus diubah. Ingat: Anda tidak dapat benar-benar memparalelkan rasa ini di komputer multicore. Itu datang ke akses disk, yang dibatasi oleh RAID atau apa pun.

polemon
sumber
1
shred tidak akan bekerja dengan banyak filesystem modern.
0

Jika Anda memiliki jutaan file dan setiap solusi di atas membuat sistem Anda stres, Anda dapat mencoba inspirasi ini:

File 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

Dan sekarang hapus file:

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

Temukan akan membuat kumpulan (lihat getconf ARG_MAX) beberapa puluh ribu file dan meneruskannya nice_delete. Ini akan membuat batch yang lebih kecil untuk memungkinkan tidur ketika kelebihan terdeteksi.

brablc
sumber
0

Jika Anda hanya ingin menyingkirkan banyak file sesegera mungkin ls -f1 /path/to/folder/with/many/files/ | xargs rmmungkin bekerja dengan baik, tetapi lebih baik jangan jalankan di sistem produksi karena sistem Anda mungkin menjadi masalah IO dan aplikasi mungkin macet selama operasi penghapusan.

Script ini berfungsi dengan baik untuk banyak file dan seharusnya tidak mempengaruhi ioload sistem.

#!/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
Leon Kramer
sumber
0

Gunakan rm -rf directorysebagai ganti rm -rf *.

Kami awalnya melakukan rm -rf *sementara di direktori untuk menghapus konten dan berpikir itu secepat mungkin. Tapi kemudian, salah satu insinyur senior kami menyarankan agar kami tidak menggunakan tanda bintang ( *) dan meneruskannya di direktori induk, seperti rm -rf directory.

Setelah beberapa perdebatan sengit tentang bagaimana itu tidak akan membuat perbedaan, kami memutuskan untuk membandingkannya, bersama dengan metode penggunaan ketiga find. Inilah hasilnya:

time rm -rf *                   2m17.32s
time rm -rf directory           0m15.60s
time find directory -delete     0m16.97s

rm -rf directorysekitar 9 KALI LEBIH CEPAT daripada rm -rf *!

Singkatnya, kami membeli bir untuk insinyur itu!

Jadi sekarang kita gunakan rm -rf directory; mkdir directoryuntuk menghapus direktori dan membuatnya kembali.

Joshua Pinter
sumber