हजारों फ़ाइलों वाली बड़ी निर्देशिका को कुशलतापूर्वक हटा दें


159

हमारे पास एक समस्या है जिसमें एक फ़ोल्डर हजारों छोटी फ़ाइलों के साथ अनजान बन जाता है।

बहुत सारी फाइलें हैं जो प्रदर्शन rm -rfमें त्रुटि देती हैं और इसके बजाय हमें जो करने की आवश्यकता है वह कुछ इस तरह है:

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

यह काम करता है लेकिन बहुत धीमा है और लगातार मेमोरी से बाहर निकलने में विफल रहता है।

क्या ऐसा करने के लिए इससे अच्छा तरीका है? आदर्श रूप में मैं इसके अंदर की सामग्री की परवाह किए बिना पूरी निर्देशिका को निकालना चाहूंगा।


16
rm -rf *बहुत सारे तर्कों के कारण फ़ोल्डर विफल हो जाता है; लेकिन क्या होगा rm -rf folder/अगर आप पूरी निर्देशिका को वैसे भी हटाना चाहते हैं?
sr_

4
मैं इसे मैन्युअल रूप से हटाने के बजाय, फ़ोल्डर को एक अलग विभाजन पर रखने का सुझाव देता हूं और बस & amp; & प्रारूप && रिमाउंट को अनमाउंट करता हूं।
bbaja42

7
जिज्ञासा से बाहर - तोड़ने के लिए कितनी फाइलें लगती हैं rm -rf?
jw013

7
आपको संभवतः कुछ और सटीक प्रश्नों का नाम बदलना चाहिए, जैसे "हजारों फ़ाइलों वाली बड़ी निर्देशिका को कुशलतापूर्वक हटाएं।" किसी निर्देशिका और उसकी सामग्री को हटाने के लिए , पुनरावर्ती परिभाषा द्वारा आवश्यक है। आप मैन्युअल रूप से केवल निर्देशिका इनकोड को स्वयं अनलिंक कर सकते हैं (शायद रूट विशेषाधिकार की आवश्यकता होती है), फ़ाइल सिस्टम को अनमाउंट करें, और fsckअप्रयुक्त डिस्क ब्लॉक को पुनः प्राप्त करने के लिए उस पर चलाएं , लेकिन यह दृष्टिकोण जोखिम भरा लगता है और कोई तेज़ नहीं हो सकता है। इसके अलावा, फ़ाइल सिस्टम चेक में फ़ाइल सिस्टम ट्री वैसे भी पुनरावृत्ति करना शामिल हो सकता है।
jw013

4
एक बार जब मेरे पास एक ccacheफ़ाइल का पेड़ इतना विशाल rmथा , और इतने लंबे समय तक ले रहा था (और पूरी प्रणाली को सुस्त बना रहा था), यह फाइलसिस्टम, प्रारूप से अन्य सभी फाइलों को कॉपी करने और उन्हें वापस कॉपी करने के लिए काफी तेज था। तब से मैं ऐसे बड़े आकार के छोटे फ़ाइल वृक्षों को अपने स्वयं के समर्पित फाइल सिस्टम देता हूं, इसलिए आप mkfsइसके बजाय सीधे कर सकते हैं rm
ठंढकुट्ज़

जवाबों:


211

Rsync का उपयोग करना आश्चर्यजनक तेज और सरल है।

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

@ सारथ के जवाब ने एक और तेज़ विकल्प का उल्लेख किया: पर्ल! इसके बेंचमार्क इससे तेज हैं 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 की तुलना में बहुत तेज़
जॉन पॉवेल

22
rsyncसादे से तेज हो सकता है rm, क्योंकि यह सही क्रम में हटाए जाने की गारंटी देता है, इसलिए कम btress recomputation की आवश्यकता होती है। यह उत्तर देखें serverfault.com/a/328305/105902
Marki555

7
किसी को एक निर्देशिका_ to_be_deleted के अंदर सभी निर्देशिकाओं और फ़ाइलों को पुन: हटाने के लिए पर्ल अभिव्यक्ति को संशोधित किया जा सकता है ?
अभिनव

5
नोट: जोड़ने के -Pकुछ और प्रदर्शन के लिए rsync के लिए, यह भी, सिंटैक्स के बारे में सावधान रहना विकल्प, अनुगामी स्लैश हैं अनिवार्य। अंत में, आप सूखी रन-n लॉन्च करने के लिए पहले विकल्प के साथ पहली बार rsync कमांड शुरू कर सकते हैं
Drasill

1
-aबराबर है -rlptgoD, लेकिन केवल हटाने के लिए -rdआवश्यक है
कोएन।

38

ट्विटर पर किसी ने -deleteइसके बजाय का उपयोग करने का सुझाव दिया-exec rm -f{} \;

यह कमांड की दक्षता में सुधार हुआ है, यह अभी भी सब कुछ के माध्यम से जाने के लिए पुनरावृत्ति का उपयोग करता है।


11
यह गैर मानक है। GNU findहै -delete, और अन्य findहो सकता है।
enzotib

13
-delete-exec rmसुरक्षा और दक्षता के कारणों के लिए हमेशा उपलब्ध होने पर प्राथमिकता दी जानी चाहिए ।
jw013

6
जीएनयू वास्तव में मानक है।
रॉनजॉन

17

क्या कुछ इस तरह के बारे में: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

आप पैरामीटर के लिए तर्क बदलकर एक बार में हटाने के लिए फ़ाइलों की संख्या सीमित कर सकते हैं -n। रिक्त के साथ फ़ाइल नाम भी शामिल हैं।


2
आपको शायद -n 20बिट्स की आवश्यकता नहीं है , क्योंकि xargs को वैसे भी स्वीकार्य तर्क-सूची आकारों तक ही सीमित होना चाहिए।
बेकार

हाँ आप सही है। यहाँ से एक नोट है 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 बफर आकार का निर्धारण नहीं कर सकते हैं या यदि निष्पादित कमांड में कुछ सीमाएँ हैं।
डिजिटल_इनफिनिटी

12

एक चतुर चाल:

rsync -a --delete empty/ your_folder/

यह सुपर सीपीयू गहन है, लेकिन वास्तव में वास्तव में तेज है। Https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-way-to-remove-huge-number-of-files.html देखें


यह इतनी जल्दी नहीं है, क्योंकि यह निर्देशिका सामग्री को कुशलतापूर्वक पढ़ता है। 10x तेज समाधान और स्पष्टीकरण के लिए इस उत्तर को देखें serverfault.com/a/328305/105902
Marki555

2
@ Marki555: प्रश्न के संपादन में इसे rsync -a --deleteबनाम 43 के लिए 60 सेकंड की सूचना दी गई है lsdent। 10x अनुपात time ls -1 | wc -l बनाम के लिए था time ./dentls bigfolder >out.txt(जो कि > fileबनाम के कारण आंशिक रूप से उचित तुलना है wc -l)।
हस्त्तूर

समस्या यह है कि वहाँ कोई नहीं वहाँ पर आदेशों की वास्तव में क्या हटाने के लिए वांछित ट्रेवर्सल आपरेशन। कोड वे देते हैं? जैसा कि 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ने कई बार (मेमोरी से बाहर) अरबों फाइलों के केवल हिस्से को हटा दिया। लेकिन कई रिट्रीट के बाद आखिरकार इसने काम किया। यदि स्मृति से बाहर समस्या है तो एकमात्र समाधान लगता है।
इरुक

6

मुझे इस समस्या -deleteकी तुलना में परीक्षण करने का अवसर मिला -exec rm \{\} \;और मेरे लिए यह अवसर -deleteथा।

-deleteकम से कम 1,000 गुना तेजी से 400,000 फ़ाइलों के फ़ोल्डर में फ़ाइलों को नष्ट करने का उपयोग करना rm

'कैसे लिनक्स में बड़ी संख्या में फ़ाइलों को हटाने के लिए' लेख से पता चलता है कि यह लगभग तीन गुना तेज है, लेकिन मेरे परीक्षण में अंतर बहुत नाटकीय था।


3
का उपयोग करते हुए find -execनिष्पादित rmहर फ़ाइल के लिए आदेश अलग से, यही कारण है कि यह इतनी धीमी गति से होता है।
मार्की 555

5

-deleteउपरोक्त विकल्प के बारे में : मैं एक अस्थायी फ़ोल्डर में बड़ी संख्या (1M + est) फ़ाइलों को हटाने के लिए इसका उपयोग कर रहा हूं जो मैंने बनाया था और अनजाने में रात को साफ करना भूल गया था। मैंने अपनी डिस्क / विभाजन को गलती से भर दिया, और कुछ और उन्हें लेकिन find .कमांड को हटा नहीं सका । यह धीमा है, पहले मैं उपयोग कर रहा था:

find . -ls -exec rm {} \;

लेकिन यह समय की एक अधिकतम राशि ले रहा था। यह कुछ फाइलों को हटाने के लिए लगभग 15 मिनट के बाद शुरू हुआ, लेकिन मेरा अनुमान है कि आखिरकार शुरू होने के बाद यह 10 या उससे कम प्रति सेकंड निकाल रहा था। तो, मैंने कोशिश की:

find . -delete

इसके बजाय, और मैं इसे अभी चलाने दे रहा हूँ। ऐसा प्रतीत होता है कि यह तेजी से चल रहा है, हालांकि यह सीपीयू पर कर लगाना है जो अन्य कमांड नहीं था। यह अब एक घंटे की तरह चल रहा है और मुझे लगता है कि मुझे अपने ड्राइव पर जगह वापस मिल रही है और विभाजन धीरे-धीरे "धीमा" हो रहा है लेकिन अभी भी बहुत समय लग रहा है। मुझे गंभीरता से संदेह है कि यह दूसरे की तुलना में 1,000 गुना तेजी से चल रहा है। जैसा कि सभी चीजों में, मैं सिर्फ अंतरिक्ष बनाम समय में ट्रेडऑफ को इंगित करना चाहता था। यदि आपके पास सीपीयू बैंडविड्थ है (हम करते हैं) तो बाद को चलाएं। यह मेरा सीपीयू चल रहा है ( uptimeरिपोर्ट):

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

और मैंने देखा है कि लोड औसत 30.00 से अधिक है, जो एक व्यस्त प्रणाली के लिए अच्छा नहीं है, लेकिन हमारे लिए जो सामान्य रूप से हल्के ढंग से भरी हुई है, यह कुछ घंटों के लिए ठीक है। मैंने सिस्टम पर अन्य चीजों की जाँच की है और वे अभी भी उत्तरदायी हैं इसलिए हम अभी के लिए ठीक हैं।


यदि आप उपयोग करने जा रहे हैं execतो आप लगभग निश्चित रूप से उपयोग नहीं करना चाहते हैं -lsऔर do find . -type f -exec rm '{}' ++ तेज है क्योंकि यह rm को कई तर्क देगा क्योंकि यह एक बार में संभाल सकता है।
एक्सनोटेरासाइड

मुझे लगता है कि आपको आगे बढ़ना चाहिए और इसे अपने स्वयं के उत्तर में संपादित करना चाहिए ... यह वास्तव में एक टिप्पणी के लिए बहुत लंबा है। इसके अलावा, यह लगता है जैसे आपके फाइलसिस्टम में काफी महंगे डिलीट हैं, उत्सुक है कि यह कौन सा है? आप इसे चला सकते हैं या इसके find … -deleteमाध्यम से मदद कर सकते हैं। इसलिए कम-क्रैश-सुरक्षित सेटिंग्स के लिए कुछ माउंट विकल्प बदल सकते हैं। (और, बेशक, और क्या फाइल सिस्टम पर है पर निर्भर करता है, सब कुछ नष्ट करने के लिए तेज तरीका अक्सर है ।)niceionicemkfs
derobert

3
लोड औसत हमेशा सीपीयू नहीं होता है, यह समय के साथ अवरुद्ध प्रक्रियाओं की संख्या का एक उपाय है। डिस्क I / O पर प्रक्रियाएं अवरुद्ध हो सकती हैं, जो कि संभावना है कि यहां क्या हो रहा है।
स्कोर_उंडर

यह भी ध्यान दें कि लोड औसत तार्किक सीपीयू की संख्या के लिए जिम्मेदार नहीं है। तो 1सिंगल-कोर मशीन के लिए लोडवॅग 6464-कोर सिस्टम पर लोडवाग के समान है - जिसका अर्थ है कि प्रत्येक सीपीयू 100% समय में व्यस्त है।
मार्की 555

3

ऐसे कई तरीके हैं, जिनका उपयोग लिनक्स में बड़ी संख्या में फ़ाइलों को हटाने के लिए किया जा सकता है। आप डिलीट ऑप्शन से पा सकते हैं, जो एक्जीक्यूट ऑप्शन से तेज है। फिर आप पर्ल अनलिंक का उपयोग कर सकते हैं, फिर rsync का भी। लिनक्स में बड़ी संख्या में फ़ाइलों को हटाने के लिए कैसे


3

Btrfs वॉल्यूम का उपयोग करने पर विचार करें और बड़ी संख्या में फ़ाइलों के साथ ऐसी डायरेक्टरी के लिए पूरी मात्रा को हटा दें।

वैकल्पिक रूप से आप एक एफएस छवि फ़ाइल बना सकते हैं और बाद में सब कुछ हटाने के लिए इसकी फाइल को हटा सकते हैं।


2

यह मानते हुए कि GNU parallelस्थापित है, मैंने इसका उपयोग किया है:

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

और यह काफी तेज था।


1

वास्तव में बड़ी निर्देशिकाओं को हटाने के लिए एक अलग दृष्टिकोण की आवश्यकता होती है, जैसा कि मैंने इस साइट से सीखा - आपको आयनिस का उपयोग करने की आवश्यकता होगी। यह सुनिश्चित करता है (-c3) कि डिलीट केवल तभी किया जाएगा जब सिस्टम में इसके लिए IO-time हो। आप सिस्टम लोड को उच्च नहीं करेंगे और सब कुछ उत्तरदायी रहता है (हालांकि मेरे सीपीयू का समय लगभग 50% अधिक था)।

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

5
+इसके बजाय का उपयोग करने से \;यह तेज़ हो जाएगा क्योंकि यह एक ही बार में आरएम के लिए अधिक तर्क पारित करता है, कम
फोर्किंग

1
क्यों नहीं ionice -c3 find <dir> -type f -delete
jtgd

0
ls -1 | xargs rm -rf 

मुख्य फ़ोल्डर के अंदर काम करना चाहिए


1
lsफ़ोल्डर में फ़ाइलों की मात्रा के कारण काम नहीं करेगा। यही कारण है कि मुझे उपयोग करना पड़ा find, हालांकि धन्यवाद।
टॉबी

4
@ टोबी: कोशिश करें ls -f, जो सॉर्टिंग को अक्षम करता है। सॉर्टिंग के लिए आवश्यक है कि संपूर्ण निर्देशिका को क्रमबद्ध करने के लिए मेमोरी में लोड किया जाए। एक अनसोल्ड lsको इसके आउटपुट को स्ट्रीम करने में सक्षम होना चाहिए।
camh

1
ऐसे फिल्नामों पर काम नहीं करता, जिनमें नई-नई कहानियाँ हैं।
मैक्सचेलपिजिग

@ सच है। लेकिन सॉर्ट किए गए क्रम में फ़ाइलों को हटाने से अनसर्टेड की तुलना में तेज़ है (प्रत्येक विलोपन के बाद निर्देशिका की बीट्री को पुन: सम्मिलित करने के कारण)। उदाहरण के लिए इस उत्तर को देखें serverfault.com/a/328305/105902
Marki555

@ maxschlepzig ऐसी फ़ाइलों के लिए जिनका आप उपयोग कर सकते हैं find . -print0 | xargs -0 rm, जो फ़ाइल नाम विभाजक के रूप में NULL char का उपयोग करेंगे।
मार्की 555

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

यह तेज़ है, मानो या न मानो, क्योंकि केवल एक इनोड को बदलना होगा। याद रखें: आप वास्तव में एक मल्टीकोर कंप्यूटर पर इस स्वाद को समानांतर नहीं कर सकते। यह डिस्क एक्सेस के लिए नीचे आता है, जो कि 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 {} \+

खोजें getconf ARG_MAXकुछ दसियों हज़ारों फ़ाइलों के बैच (देखें ) बनाएंगे और इसे पास करेंगे nice_delete। यह अधिभार का पता चलने पर सोने की अनुमति देने के लिए और भी छोटे बैचों का निर्माण करेगा।


0

यदि आप जल्द से जल्द कई फाइलों से छुटकारा पाना चाहते हैं ls -f1 /path/to/folder/with/many/files/ | xargs rm, तो ठीक है, लेकिन बेहतर होगा कि इसे प्रोडक्शन सिस्टम पर न चलाएं क्योंकि आपका सिस्टम IO समस्या बन सकता है और एप्लिकेशन डिलीट ऑपरेशन के दौरान अटक सकते हैं।

यह स्क्रिप्ट कई फ़ाइलों के लिए अच्छी तरह से काम करती है और सिस्टम के आईओलाड को प्रभावित नहीं करना चाहिए।

#!/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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.