Binlerce dosya içeren büyük dizini etkin bir şekilde silin


159

Bir klasörde, yüzbinlerce küçük dosya ile hantallaşmak konusunda bir sorunumuz var.

rm -rfBir hata döndüren birçok dosya var ve bunun yerine yapmamız gereken şey şunun gibi:

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

Bu çalışır, ancak çok yavaş ve sürekli bellek yetersiz kalıyor.

Bunu yapmanın daha iyi bir yolu var mı? İdeal olarak, içindeki dizini önemsemeden tüm dizini kaldırmak istiyorum.


16
rm -rf *klasörde muhtemelen çok fazla argüman nedeniyle başarısız oluyor; peki ya rm -rf folder/yine de tüm dizini silmek istersen?
sr_

4
Manuel olarak silmek yerine, klasörü ayrı bir bölümde bulundurmanızı ve && format && remount'un bağlantısını kesmenizi öneririm.
bbaja42

7
Sadece meraktan - kırmak için kaç dosya gerekir rm -rf?
jw013

7
Muhtemelen soruyu daha doğru bir şeyle yeniden adlandırmalısınız, "Binlerce dosya içeren büyük dizini verimli bir şekilde silin." Bir dizini ve içeriğini silmek için tanım gereği özyineleme gereklidir. Yalnızca dizin inode'un kendisinin bağlantısını kaldırabilir (muhtemelen kök ayrıcalıkları gerektirir), dosya sisteminin bağlantısını fsckkesebilir ve kullanılmayan disk bloklarını geri almak için üzerinde çalışabilirsiniz , ancak bu yaklaşım riskli görünebilir ve daha hızlı olmayabilir. Ek olarak, dosya sistemi kontrolü, dosya sistemi ağacını yine de yinelemeli olarak geçirmeyi içerebilir.
jw013

4
Bir keresinde ccacheçok büyük bir dosya ağacım vardı ve rmçok uzun sürüyordu (ve tüm sistemi durgunlaştırıyordu), diğer tüm dosyaları dosya sisteminden kopyalamak, biçimlendirmek ve geri kopyalamak çok daha hızlıydı. O zamandan beri böyle büyük küçük dosya ağaçlarına kendilerine adanmış dosya sistemlerini veriyorum, böylece mkfsdoğrudan yerine rm.
frostschutz

Yanıtlar:


211

Rsync kullanımı hızlı ve basittir.

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

@ sarath'ın cevabı başka bir hızlı seçimden bahsetti: Perl! Kıyaslamaları daha hızlı rsync -a --delete.

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

Kaynaklar:

  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
Teşekkürler, çok yararlı. Her zaman rsync kullanıyorum, bu şekilde silmek için kullanabileceğini hiç bilmiyordum. Rm -rf'den çok daha hızlı
John Powell

22
rsyncrmdüzden daha hızlı olabilir , çünkü silmelerin doğru sırayla yapılmasını garanti eder, bu nedenle daha az btress yeniden hesaplanması gerekir. Bu cevabı gör serverfault.com/a/328305/105902
Marki555

7
Herkes yinelemeli bir içindeki tüm dizinleri ve dosyaları silmek için perl ifadeyi değiştirebilir directory_to_be_deleted ?
Abhinav

5
Notlar: eklemek -P, ayrıca, biraz daha görüntü için rsync sözdizimi hakkında dikkatli olmak seçeneği, sondaki eğik çizgi vardır zorunlu. Son olarak, kuru çalışmayı-n başlatmak için ilk seçenek olan rsync komutunu ilk kez başlatabilirsiniz .
Drasill

1
-aeşittir -rlptgoD, ancak silmek için sadece -rdgereklidir
Koen.

38

Birileri Twitter'da kullanarak önerdi -deleteyerine-exec rm -f{} \;

Bu komutun etkinliğini arttırdı, yine de her şeye devam etmek için özyinelemeyi kullanıyor.


11
Bu standart değil. GNU findvar belki de -deletebaşka find.
enzotib

13
-delete-exec rmGüvenlik ve verimlilik nedeniyle her zaman mümkün olduğunda tercih edilmeli .
jw013

6
GNU, fiili standarttır.
RonJohn

17

Peki ya böyle bir şey: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Parametre için argümanı değiştirerek bir kerede silinecek dosya sayısını sınırlayabilirsiniz -n. Ayrıca boşluk içeren dosya adları da bulunur.


2
Muhtemelen -n 20bit ihtiyacınız yoktur , çünkü xargs yine de kendini kabul edilebilir argüman listesi boyutlarıyla sınırlandırmalıdır.
İşe yaramaz

Evet haklısın. İşte bir nottur 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. Bu nedenle, -nseçenek, xargs'ın CLI arabellek boyutunu belirleyemediği durumlarda veya exec komutunun bazı sınırlamaları varsa.
digital_infinity

12

Akıllıca bir numara:

rsync -a --delete empty/ your_folder/

Süper işlemci yoğun, ama gerçekten çok hızlı. Bkz https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html


Çok hızlı değil, çünkü dizin içeriğini verimli bir şekilde okuyor. 10x daha hızlı çözüm ve açıklama için bu cevaba bakınız serverfault.com/a/328305/105902
Marki555

2
@ Marki555: Sorunun Düzenlenmesinde 60 saniye için rsync -a --delete43 saniye rapor edildi lsdent. 10x oranı time ls -1 | wc -l vs içindi time ./dentls bigfolder >out.txt(yani > filevs nedeniyle kısmen adil bir karşılaştırma wc -l).
Hastur

Sorun şu ki orada YOK orada komutların aslında DO silinmesi için istenen geçişi işlemi. Verdikleri kod mu? Marki555 tarafından tanımlandığı şekilde ÇALIŞMAYIN.
Svartalf

11

Yorumlardan birini genişleterek, yaptığını düşündüğün şeyi yaptığını sanmıyorum.

İlk önce durumunuzu simüle etmek için çok miktarda dosya oluşturdum:

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

Sonra, başarısız olmayı umduğum şeyi ve soruda yaptığınız gibi göründüğünü denedim:

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

Ama bu yapar işi:

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

6
İşe yarayan tek çözüm bu: rm -Rf bigdirectoryBirkaç kez çalıştırın . Binlerce milyon alt dizin ve dosya içeren bir rehberim vardı. Bu dizinde bile çalışamamıştım, lsya findda rsynchafızası tükendi çünkü. Komut rm -Rf, yalnızca milyarlarca dosyanın yalnızca bir bölümünü silerek birçok kez çıkar (bellek yetersiz). Ancak birçok denemeden sonra nihayet işi yaptı. Sorun azalıyorsa sorun tek çözüm gibi görünüyor.
erik

6

Ben test etmek için fırsat vardı -deletekıyasla -exec rm \{\} \;ve benim için -deletebu sorunun cevabı oldu.

Kullanma -deleteen az 1000 kat daha hızlı daha 400,000 dosyaları bir klasöre dosya silinmiş rm.

'Linux'ta çok sayıda dosya nasıl silinir' makalesi, bunun yaklaşık üç kat daha hızlı olduğunu ancak testimde farkın çok daha çarpıcı olduğunu gösteriyor.


3
Kullanılması find -execyürütür rmo kadar yavaş olmasının nedeni ayrı her dosya için komut, bu.
Marki555

5

Hakkında -deleteOluşturduğum ve yanlışlıkla gece temizleme unuttum geçici klasörde çok sayıda (1M + est) dosyaları kaldırmak için kullanıyorum: Yukarıdaki seçenek. Diskimi / diskimi kazayla doldurdum ve find .komuttan başka bir şey onları kaldıramadı . Yavaş, ilk başta kullanıyordum:

find . -ls -exec rm {} \;

Fakat bu, çok fazla zaman alıyordu. Bazı dosyaları kaldırmak için yaklaşık 15 dakika sonra başladı, ancak benim tahminime göre nihayet başladıktan sonra saniyede 10 ya da daha azını kaldırıyordu. Bu yüzden denedim:

find . -delete

Bunun yerine, ve şimdi çalışmasına izin veriyorum. Daha hızlı çalışıyor gibi gözükse de, diğer komutun olmadığı CPU'da ÇOK vergilendiriliyor. Şimdi bir saattir çalışıyor ve sanırım diskime yeniden yer açıyorum ve bölüm yavaş yavaş "zayıflıyor" fakat hala çok uzun sürüyor. Cidden diğerinden 1000 kat daha hızlı çalıştığından şüpheliyim. Her şeyde olduğu gibi, ben zamana karşı uzayda yaşanan değişimi işaret etmek istedim. Yedeklemek için CPU bant genişliğiniz varsa (yaparız), ikincisini çalıştırın. İşlemcim çalışıyor ( uptimeraporlar):

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

Ve yük ortalamasının 30.00'ın üzerinde olduğunu gördüm, bu da yoğun bir sistem için iyi değil, normalde hafif yüklenen bizim için birkaç saat için sorun değil. Sistemdeki diğer birçok şeyi kontrol ettim ve hala yanıt veriyorlar, bu yüzden şimdilik iyiyiz.


Eğer seni kullanacaksan execneredeyse kesinlikle kullanmak istemezsin -lsve yapmak find . -type f -exec rm '{}' ++ daha hızlıdır, çünkü bir kerede halledebileceği kadar rm için birçok argüman verecektir.
xenoterracide

Bence devam edip bunu kendi cevabına göre düzenlemelisin… yorum yapmak için gerçekten çok uzun. Ayrıca, dosya sisteminizde oldukça pahalı silme sesleri var, hangisi olduğunu merak ediyor musunuz? Bunu çalıştırabilir find … -deletearacılığıyla niceya ionice, o yardımcı olabilir. Bu nedenle, bazı montaj seçeneklerini daha az kilitlenmeyan ayarlara değiştirmek olabilir. (Ve, elbette, dosya sistemindeki başka ne olduğuna bağlı olarak, her şeyi silmenin en hızlı yolu genellikle) mkfs.
derobert

3
Yük ortalaması her zaman CPU değildir, sadece zaman içinde engellenen işlem sayısının bir ölçütüdür. İşlemler disk g / Ç'de engellenebilir, bu muhtemelen burada olanları gösterir.
Score_Under

Ayrıca, ortalama yükün mantıksal CPU sayısını hesaba katmadığını unutmayın. Bu nedenle 1, tek çekirdekli makine için loadavg 64, 64 çekirdekli sistemdeki loadavg ile aynıdır - yani her bir CPU zamanın% 100'ünü meşgul eder.
Marki555

3

Linux'ta çok sayıda dosyayı silmek için kullanılabilecek birkaç yöntem vardır. Exec seçeneğinden daha hızlı olan delete (sil) seçeneğiyle kullanabilirsiniz. Sonra perl unlink, ardından rsync kullanabilirsiniz. Linux'ta çok sayıda dosya nasıl silinir


3

Btrfs hacmini kullanmayı düşünün ve çok sayıda dosya içeren böyle bir dizinin tüm birimini silin.

Alternatif olarak, bir FS görüntü dosyası oluşturabilir, ardından bir kerede çok hızlı bir şekilde her şeyi kaldırmak için bağlantısını açıp silebilirsiniz.


2

GNU’nun parallelkurulu olduğunu varsayarak , bunu kullandım:

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

ve yeterince hızlıydı.


1

GERÇEKTEN BÜYÜK dizinlerin silinmesi, bu siteden öğrendiğim gibi, farklı bir yaklaşıma ihtiyaç duyuyor - iyonice kullanmanız gerekecek. Sistemlerin yükü yükselmeyecek ve her şey yanıt vermeye devam edecektir (bulma için CPU zamanım yaklaşık% 50'de oldukça yüksekti).

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

5
kullanarak +yerine \;o, bir kerede daha az çatallaşma rm fazla argümanlar geçerken daha hızlı bu kılacak
xenoterracide

1
Neden olmasın ionice -c3 find <dir> -type f -delete
jtgd

0
ls -1 | xargs rm -rf 

ana klasörün içinde çalışmalı


1
lsklasördeki dosyaların miktarı nedeniyle çalışmaz. Bu yüzden kullanmak zorunda kaldım find, yine de teşekkürler.
Toby,

4
@Toby: ls -fSıralamayı devre dışı bırakmayı dene . Sıralama, dizinin tamamının sıralanacak belleğe yüklenmesini gerektirir. Sıralanmamış bir lsçıktı verebilmeli.
Camh

1
Yeni satırları içeren dosya adları üzerinde çalışmaz.
maxschlepzig

@ camh bu doğru. Ancak dosyaları sıralı düzende silmek sıralamasızdan daha hızlıdır (her silme işleminden sonra dizinin btree değerini yeniden hesaplamak nedeniyle). Bu cevaba bakınız: serverfault.com/a/328305/105902
Marki555

@ maxschlepzig find . -print0 | xargs -0 rm, NULL karakterini dosya adı ayırıcısı olarak kullanacak , bu tür dosyalar için kullanabilirsiniz .
Marki555,

0

Izkata'nın yukarıdaki ipucu için:

Ama bu yapar işi:

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

Bu neredeyse işe yaradı - ya da işe yarayabilirdi - ama izinlerde bazı problemlerim vardı; dosyalar bir sunucudaydı, ancak yine de bu izin sorununun nereden geldiğini anlamıyorum. Neyse, Terminal her dosya için onay istedi. Dosya miktarı yaklaşık 20 000 idi, bu nedenle bu bir seçenek değildi. "-R" 'den sonra "-f" opsiyonunu ekledim, bu yüzden tüm komut " rm -r -f foldername / " idi. Sonra iyi iş gibi görünüyordu. Terminal ile acemi biriyim, ama sanırım bu tamam, değil mi? Teşekkürler!


0

Bu dosyalardan ne kadar kurtulmanız gerektiğine bağlı olarak kullanmanızı öneririm shred.

$ shred -zuv folder

dizini silmek istiyorsanız, ancak onu kaldıramaz ve yeniden oluşturamazsanız, onu taşımanızı ve anında yeniden oluşturmanızı öneririm.

mv folder folder_del
mkdir folder
rm -rf folder_del

bu daha hızlı, sadece bir inode değişmesi gerektiğine inan veya inanma. Unutmayın: Bu tadı çok çekirdekli bir bilgisayarda gerçekten paralel hale getiremezsiniz. RAID ile sınırlandırılmış olan disk erişimine veya sizin elinizde olan şeylere gelir.


1
shred birçok modern dosya sistemiyle çalışmayacak .

0

Milyonlarca dosyanız varsa ve yukarıdaki her çözüm sisteminizi strese sokarsa, bu ilham kaynağını deneyebilirsiniz:

Dosya 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

Ve şimdi dosyaları silin:

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

Bul, getconf ARG_MAXon binlerce dosyadan oluşan toplu işlemler (bkz. ) Oluşturur ve iletir nice_delete. Bu, aşırı yük tespit edildiğinde uykuya izin vermek için daha küçük gruplar oluşturacaktır.


0

Mümkün olan en kısa sürede birçok dosyadan kurtulmak istiyorsanız, ls -f1 /path/to/folder/with/many/files/ | xargs rmtamam işe yarayabilir, ancak üretim sistemlerinde çalıştırmayın, çünkü sisteminiz IO sorunları olabilir ve silme işlemi sırasında uygulamalar takılabilir.

Bu komut dosyası birçok dosya için iyi çalışıyor ve sistemin yükünü etkilememelidir.

#!/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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.