Menghapus jutaan file

38

Saya memiliki dir yang diisi dengan jutaan gambar gif. Terlalu banyak untuk perintah rm.

Saya telah mencoba perintah find seperti ini:

find . -name "*.gif" -print0 | xargs -0 rm

Masalahnya, mesin saya rusak parah, dan menyebabkan waktu habis bagi pelanggan karena itu server.

Apakah ada cara yang lebih cepat untuk menghapus semua file ini ... tanpa mengunci mesin?

Corepuncher
sumber
Saya berada pada tingkat penghapusan sekitar 6 gb / jam menggunakan perintah "nice find" di bawah ini. Mungkin akan memakan waktu 48 jam langsung untuk menyingkirkan semua file. Alasannya adalah skrip penjelajahan gagal. Saya telah melampaui "event horizon" dengan perintah rm, lalu melarikan diri
3
Apakah menghapus seluruh dir tidak jauh lebih cepat? Keluarkan saja file-file "bagus" sebelum menghapus yang tersisa ...
tucuxi
Yah, setiap file buruk sekarang, karena dipindahkan ke / dir_old, dan saya membuat ulang / dir. Tetapi bukankah rmdir akan mengalami batasan yang sama dengan rm *?
@Corepuncher: Saya berharap bahwa menghapus seluruh direktori (seperti dengan rm -rfakan lebih cepat. Ini patut dicoba.
Jason R
Saya sedang menjalankan "rm -rf" di direktori tersebut. Sudah berjalan selama lebih dari 20 menit sekarang ... belum ada perubahan ukuran disk. Tetapi juga itu tidak secara otomatis mengembalikan "daftar argumen terlalu lama". Satu-satunya masalah adalah, itu benar-benar memalu mesin saya dan membuat hal-hal lain lambat / gagal. Tidak yakin berapa lama untuk membiarkannya.

Jawaban:

44

Lebih cepat belum tentu apa yang Anda inginkan. Anda mungkin ingin benar-benar berjalan lebih lambat , sehingga penghapusan mengunyah lebih sedikit sumber daya saat sedang berjalan.

Gunakan nice (1) untuk menurunkan prioritas perintah.

nice find . -name "*.gif" -delete

Untuk proses I / O-terikat bagus (1) mungkin tidak cukup. Penjadwal Linux memang memperhitungkan I / O, bukan hanya CPU, tetapi Anda mungkin ingin kontrol yang lebih baik atas prioritas I / O.

ionice -c 2 -n 7 find . -name "*.gif" -delete

Jika itu tidak berhasil, Anda juga bisa menambahkan tidur untuk memperlambatnya.

find . -name "*.gif" -exec sleep 0.01 \; -delete
John Kugelman mendukung Monica
sumber
3
wow ... jutaan file dengan sleep .1 s ... membutuhkan sehari untuk 864000 file.
glglgl
7
@glglgl Baiklah, pantat pintar. Saya mengubah batas waktu. :-P
John Kugelman mendukung Monica
28
Tidur mungkin merupakan pilihan yang baik, tetapi menyenangkan tidak akan berhasil, karena tugas di sini terikat IO, bukan terikat CPU; Anda dapat mencoba ionice sebagai gantinya. Perhatikan bahwa jika tidur terlalu kecil itu akan sia-sia.
Matteo Italia
3
@glglgl: intinya adalah bahwa jika Anda tidak ingin menyebabkan gangguan layanan pada server Anda harus pergi perlahan, waktu di mana kode ini tidur ada untuk membiarkan server benar-benar berguna bekerja dengan disk.
Matteo Italia
1
+1 untuk sleeptambahan - Saya mengalami masalah dengan server yang tersedak IO meskipun menggunakan ionice -c 3. Itu menambah secara signifikan waktu yang diperlukan untuk menghapus file (tentu saja), tapi saya lebih suka menunggu daripada membawa aplikasi ke bawah ...
Ola Tuvesson
22

Karena Anda menjalankan Linux dan tugas ini mungkin terikat I / O, saya menyarankan untuk memberikan prioritas penjadwal I / O perintah Anda menggunakan ionice(1):

ionice -c3 find . -name '*.gif' -delete

Dibandingkan dengan perintah awal Anda, saya kira ini bahkan dapat meluangkan lebih banyak siklus CPU dengan menghindari pipa xargs.


sumber
@Braiam Apa maksudmu? Ini bukan find ... -exectempat yang masuk akal.
Oh, ya, maaf. Salahku. Anda yakin itu efisien, bukan?
Braiam
1
Nah, find(1)dokumentasi mengklaim demikian. :) Dan harus jelas bahwa membiarkan finddirinya sendiri menghapus file lebih efisien daripada meminta rmperintah untuk ini.
1
Saya sudah mencoba beberapa versi yang disarankan pada folder dengan 4 juta file di server produksi dan ini adalah satu-satunya yang tidak mencekik sistem. ionice -c3menurunkan prio untuk hanya berjalan ketika IO idle sebaliknya jadi ini sempurna. Perhatikan bahwa karena -deleteini bukan standar untuk find, Anda dapat melakukan hal yang sama (termasuk umpan balik yang berfungsi) menggunakan perintah ini: ionice -c 3 find . -name '*.gif' -exec echo {} \; -exec rm {} \;- Pelan tapi tidak ada proses informasi penting.
Christopher Lörken
13

Tidak.

Tidak ada cara yang lebih cepat, mulai dari format lunak disk. File diberikan ke rm sekaligus (hingga batas baris perintah, bisa juga diatur ke xargs) yang jauh lebih baik daripada memanggil rm pada setiap file. Jadi tidak, pasti tidak ada cara yang lebih cepat.

Menggunakan nice(atau renicepada proses yang berjalan) hanya membantu sebagian, karena itu adalah untuk menjadwalkan sumber daya CPU , bukan disk! Dan penggunaan CPU akan sangat rendah. Ini adalah kelemahan linux - jika satu proses "menggerogoti" disk (yaitu banyak bekerja dengan itu), seluruh mesin macet. Kernel yang dimodifikasi untuk penggunaan waktu nyata bisa menjadi solusi.

Apa yang akan saya lakukan di server adalah membiarkan proses lain melakukan pekerjaannya secara manual - sertakan jeda untuk menjaga server "bernafas":

find . -name "*.gif" > files
split -l 100 files files.
for F in files.* do
    cat $F | xargs rm
    sleep 5 
done

Ini akan menunggu 5 detik setelah setiap 100 file. Ini akan memakan waktu lebih lama tetapi pelanggan Anda seharusnya tidak melihat adanya keterlambatan.

Tomas
sumber
"File-file itu diberikan kepada rm sekaligus (hingga batas baris perintah" —jadi ketika shell diperintahkan untuk rm *, ia mengembang *ke baris dengan semua nama file dan meneruskannya ke rm? Itu sangat bodoh. Mengapa shell perluas wildcard?
:-D @Joker_vD, apakah Anda bercanda, seperti yang disarankan nama Anda? :-)
Tomas
2
@ Joker_vD: Kompatibilitas dengan keputusan Unix dari tahun 1970 atau lebih. Windows tidak melakukannya. Di sana, program dapat meneruskan wildcard ke FindNextFile / FindNextFile, sehingga mereka mendapatkan hasilnya satu per satu.
MSalters
@ Thomas Tidak dalam kasus ini. Jujur, saya bisa melihat 2 masalah dengan desain seperti itu segera: pertama, baris perintah bukan karet; kedua, program tidak dapat menentukan apakah ia dipanggil dengan *atau /*dan memberikan keraguan terhadap keputusan pengguna tersebut.
1
@ Joker_vD Ada banyak hal baik tentang shell yang melakukan ekspansi wildcard. Ini berbeda dari Windows, tetapi jangan langsung menyimpulkan bahwa itu sangat bodoh hanya karena berbeda dari yang biasa Anda lakukan. Jika Anda ingin tahu lebih banyak, saya sarankan Anda untuk Google atau mengirim pertanyaan di situs Stack Exchange yang relevan. Ini adalah penggelinciran besar untuk area komentar ini.
John Kugelman mendukung Monica
5

Jika jumlah file yang akan dihapus jauh melebihi jumlah file yang tertinggal, itu mungkin bukan pendekatan yang paling efisien untuk berjalan di pohon file yang akan dihapus dan melakukan semua pembaruan sistem file tersebut. (Ini analog dengan melakukan manajemen memori kalkulasi-referensi yang kikuk, mengunjungi setiap objek di pohon besar untuk menjatuhkan referensi, alih-alih membuat segala sesuatu yang tidak diinginkan menjadi sampah dalam satu langkah, dan kemudian menyapu apa yang dapat dibersihkan dengan mudah.)

Artinya, mengkloning bagian-bagian pohon yang harus disimpan ke volume lain. Buat kembali sistem file yang baru dan kosong pada volume asli. Salin file yang disimpan kembali ke jalur aslinya. Ini agak mirip dengan menyalin pengumpulan sampah .

Akan ada beberapa downtime, tetapi bisa lebih baik daripada kinerja buruk dan gangguan layanan terus menerus.

Mungkin tidak praktis dalam sistem dan situasi Anda, tetapi mudah untuk membayangkan kasus-kasus nyata di mana ini adalah jalan yang harus ditempuh.

Sebagai contoh, misalkan Anda ingin menghapus semua file dalam sistem file. Apa gunanya mengulang dan menghapus satu per satu? Lepas saja dan lakukan "mkfs" di atas partisi untuk membuat sistem file kosong.

Atau misalkan Anda ingin menghapus semua file kecuali setengah lusin file penting? Dapatkan setengah lusin keluar dari sana dan ... "mkfs" di atas.

Akhirnya ada beberapa titik impas ketika ada cukup file yang harus tetap, sehingga menjadi lebih murah untuk melakukan penghapusan rekursif, dengan mempertimbangkan biaya lain seperti downtime.

Kaz
sumber
4

Sudahkah Anda mencoba:

find . -name "*.gif" -exec rm {} +

Tanda + di bagian akhir akan menyebabkan find menyertakan lebih banyak file untuk perintah rm tunggal yang akan dieksekusi. Periksa pertanyaan ini untuk lebih jelasnya.

Bartosz Firyn
sumber
Eksekusi lebih cepat dari -print0 | xargs solusi karena proses rm tidak dipanggil untuk setiap file tetapi untuk set besar dari mereka dan karena itu menyebabkan beban lebih rendah.
@JohnKugelman Anda benar, tetapi ekstensi GNU yang tidak selalu tersedia dengan perintah find asli .
CodeGnome
OK, menarik, tetapi ini adalah hal yang cukup baru (dan juga -delete) yang tidak selalu harus ada di sana ..
Tomas
Namun ini tentu saja tidak menghasilkan yang lebih baik dibandingkan dengan solusi OP.
Tomas