हटाएं सभी लेकिन सबसे हाल ही में एक्स फ़ाइलों को बैश में


157

वहाँ एक साधारण तरीका है, एक मानक मानक में bash के साथ UNIX वातावरण, एक निर्देशिका से सभी लेकिन सबसे हाल ही में एक्स फ़ाइलों को हटाने के लिए एक कमांड चलाने के लिए?

कुछ अधिक ठोस उदाहरण देने के लिए, हर घंटे एक निर्देशिका के लिए एक फ़ाइल (जैसे, एक लॉग फ़ाइल या एक टार-एड बैकअप) फ़ाइल लिखने की कल्पना करें। मैं एक और क्रोन जॉब चलाने का तरीका चाहूंगा जो उस निर्देशिका की सबसे पुरानी फाइलों को तब तक हटा देगा, जब तक कि 5 से कम न हो।

और स्पष्ट होने के लिए, केवल एक फ़ाइल मौजूद है, इसे कभी भी हटाया नहीं जाना चाहिए।

जवाबों:


117

मौजूदा जवाब के साथ समस्याओं:

  • एम्बेडेड स्थानों या newlines के साथ फ़ाइल नाम को संभालने में असमर्थता।
    • ऐसे समाधानों के मामले में, जो rmएक अनछुए कमांड प्रतिस्थापन ( rm `...`) पर सीधे आह्वान करते हैं , अनजाने ग्लोबिंग का एक अतिरिक्त जोखिम है।
  • फ़ाइलों और निर्देशिकाओं के बीच अंतर करने में असमर्थता (यानी, अगर निर्देशिका 5 सबसे हाल ही में संशोधित फाइल सिस्टम आइटमों में से हुई, तो आप प्रभावी रूप से 5 से कम फ़ाइलों को बनाए रखेंगे , और rmनिर्देशिकाओं पर लागू करना विफल हो जाएगा)।

wnoise का उत्तर इन मुद्दों को संबोधित करता है, लेकिन समाधान GNU -specific (और काफी जटिल) है।

यहाँ एक व्यावहारिक, POSIX- आज्ञाकारी समाधान है जो केवल एक चेतावनी के साथ आता है : यह एम्बेडेड सुर्खियों में फाइलनेम को संभाल नहीं सकता है - लेकिन मैं नहीं समझता कि अधिकांश लोगों के लिए एक वास्तविक दुनिया की चिंता।

रिकॉर्ड के लिए, यहां यह स्पष्टीकरण दिया गया है कि आम तौर पर lsआउटपुट को पार्स करने के लिए यह एक अच्छा विचार क्यों नहीं है : http://mywiki.wooledge.org/ParsingLs

ls -tp | grep -v '/$' | tail -n +6 | xargs -I {} rm -- {}

उपरोक्त अक्षम है , क्योंकि प्रत्येक फ़ाइलनाम के लिए एक बार xargsआह्वान करना पड़ता है । आपके मंच की मदद से आप इस समस्या को हल कर सकते हैं:rm
xargs

यदि आपके पास GNU है xargs , तो उपयोग करें -d '\n', जो xargsप्रत्येक इनपुट लाइन को एक अलग तर्क मानता है, फिर भी उतने ही तर्कों को पारित करता है जितना एक कमांड लाइन पर फिट होगा :

ls -tp | grep -v '/$' | tail -n +6 | xargs -d '\n' -r rm --

-r( --no-run-if-empty) सुनिश्चित करता है कि rmअगर कोई इनपुट नहीं है तो इसे लागू नहीं किया जाएगा।

यदि आपके पास बीएसडी xargs (सहित MacOS ), तो आप उपयोग कर सकते हैं -0संभाल करने NUL-separated इनपुट, के लिए सबसे पहले अनुवाद नई-पंक्तियों के बाद NUL( 0x0जो भी गुजरता है (आमतौर पर) सभी फ़ाइल नाम) वर्ण,। एक ही बार में (भी जीएनयू साथ काम xargs):

ls -tp | grep -v '/$' | tail -n +6 | tr '\n' '\0' | xargs -0 rm --

स्पष्टीकरण:

  • ls -tpफाइलसिस्टम आइटम के नामों को प्रिंट करता है कि हाल ही में उन्हें किस तरह से संशोधित किया गया था, अवरोही क्रम में (सबसे हाल ही में संशोधित आइटम पहले) ( -t), एक /निशान के साथ मुद्रित निर्देशिकाओं के रूप में उन्हें इस तरह चिह्नित करने के लिए ( -p)।
  • grep -v '/$'फिर परिणामी सूची से निर्देशिकाओं को निकाल कर, -vएक अनुगामी /( /$) रेखाओं को छोड़ कर ( ) छोड़ दिया जाता है ।
    • कैविएट : चूंकि एक सिम्लिंक जो एक निर्देशिका को इंगित करता है, वह तकनीकी रूप से स्वयं एक निर्देशिका नहीं है, ऐसे सिम्बलिंक्स को बाहर नहीं किया जाएगा।
  • tail -n +6सूची में पहले 5 प्रविष्टियों को छोड़ देता है , सभी को वापस करने में, लेकिन यदि हाल ही में संशोधित की गई 5 सबसे अधिक फाइलें हैं।
    ध्यान दें कि Nफ़ाइलों को बाहर करने के लिए, पास N+1होना चाहिए tail -n +
  • xargs -I {} rm -- {}(और इसके रूपांतर) फिर rmइन सभी फाइलों पर आक्रमण करता है ; अगर कोई मैच xargsनहीं हैं , तो कुछ भी नहीं करेंगे।
    • xargs -I {} rm -- {}प्लेसहोल्डर को परिभाषित करता है {}जो प्रत्येक इनपुट लाइन को पूरे के रूप में प्रस्तुत करता है , इसलिए rmप्रत्येक इनपुट लाइन के लिए एक बार इनवॉइस किया जाता है, लेकिन एम्बेडेड स्थानों के साथ फ़ाइल नाम सही तरीके से संभाला जाता है।
    • --सभी मामलों में यह सुनिश्चित करता है कि किसी भी फ़ाइल नाम उस के साथ शुरू करने के लिए होने -के लिए गलत नहीं कर रहे हैं विकल्पों से rm

एक बदलाव के मूल समस्या पर, मामले में मिलान फ़ाइलें संसाधित करने की आवश्यकता को व्यक्तिगत रूप से या एकत्र एक खोल सरणी में :

# One by one, in a shell loop (POSIX-compliant):
ls -tp | grep -v '/$' | tail -n +6 | while IFS= read -r f; do echo "$f"; done

# One by one, but using a Bash process substitution (<(...), 
# so that the variables inside the `while` loop remain in scope:
while IFS= read -r f; do echo "$f"; done < <(ls -tp | grep -v '/$' | tail -n +6)

# Collecting the matches in a Bash *array*:
IFS=$'\n' read -d '' -ra files  < <(ls -tp | grep -v '/$' | tail -n +6)
printf '%s\n' "${files[@]}" # print array elements

2
निश्चित रूप से अधिकांश अन्य उत्तरों की तुलना में यहां बेहतर है, इसलिए मैं अपना समर्थन उधार देने के लिए खुश हूं, यहां तक ​​कि मैं न्यूलाइन मामले को नजरअंदाज करने को केवल सावधानी के साथ किए जाने वाली चीज मानता हूं।
चार्ल्स डफी

2
यदि आप lsवर्तमान निर्देशिका में नहीं हैं, तो फ़ाइलों के पथ में '/' होगा, जिसका अर्थ है कि grep -v '/'कुछ भी मेल नहीं खाएगा। मेरा मानना grep -v '/$'है कि आप केवल निर्देशिका को बाहर करना चाहते हैं।
Waldol1

1
@ Waldol1: धन्यवाद; मैंने आपके सुझाव को शामिल करने के लिए उत्तर को अपडेट कर दिया है, जो grepकमांड को वैचारिक रूप से भी स्पष्ट करता है। हालाँकि, नोट करें कि आपके द्वारा बताई गई समस्या एकल निर्देशिका पथ के साथ सामने नहीं आएगी ; उदाहरण के लिए, ls -p /private/varअभी भी केवल फ़ाइल नाम मुद्रित करेगा। केवल यदि आपने कई फ़ाइल तर्क पारित किए (आमतौर पर एक ग्लोब के माध्यम से) तो क्या आपको आउटपुट में वास्तविक रास्ते दिखाई देंगे; उदाहरण के लिए, ls -p /private/var/*(और आप उप-मिलानों की सामग्री भी देखेंगे, जब तक कि आप भी शामिल न हों -d)।
mklement0

108

एक निर्देशिका में सबसे हाल की फ़ाइलों के सभी लेकिन 5 (या जो भी संख्या) निकालें।

rm `ls -t | awk 'NR>5'`

2
मुझे इसकी ज़रूरत केवल अपनी आर्काइव फ़ाइलों पर विचार करने के लिए थी। परिवर्तन ls -tकरने के लिएls -td *.bz2
जेम्स टी स्नेल

3
मैंने इसे rm -rf में बदलकर निर्देशिकाओं के लिए उपयोग किया ls -t | awk 'NR>1'(मैं केवल सबसे हाल ही में चाहता था)। धन्यवाद!

11
ls -t | awk 'NR>5' | xargs rm -f यदि आप पाइप पसंद करते हैं और आपको त्रुटि को दबाने की आवश्यकता है यदि हटाए जाने के लिए कुछ भी नहीं है।
H2ONaCl

16
संक्षिप्त और पठनीय, शायद, लेकिन उपयोग करने के लिए खतरनाक; यदि बनाई गई फ़ाइल को हटाने की कोशिश की जा रही है touch 'hello * world', तो यह वर्तमान निर्देशिका में बिल्कुल सब कुछ हटा देगा ।
चार्ल्स डफी

1
भले ही 2008 में इसका जवाब दिया गया था, यह एक आकर्षण की तरह काम करता है और मुझे एक विशिष्ट निर्देशिका से पुराने बैकअप को हटाने के लिए बस जरूरत थी। बहुत बढ़िया।
रेंस टिलमैन

86
(ls -t|head -n 5;ls)|sort|uniq -u|xargs rm

यह संस्करण रिक्त स्थान वाले नामों का समर्थन करता है:

(ls -t|head -n 5;ls)|sort|uniq -u|sed -e 's,.*,"&",g'|xargs rm

20
यह कमांड नामों में रिक्त स्थान के साथ फाइलों को सही ढंग से संभाल नहीं पाएगा।
tylerl

5
(ls -t|head -n 5;ls)एक कमांड ग्रुप है । यह 5 सबसे हाल की फाइलों को दो बार प्रिंट करता है। sortसमान रेखाएँ एक साथ रखता है। uniq -uडुप्लिकेट को हटाता है, ताकि सभी 5 सबसे हाल की फाइलें बनी रहें। उनमें से प्रत्येक पर xargs rmकॉल rmकरता है।
फेबियन

15
यह आपकी सभी फ़ाइलों को हटा देता है यदि आपके पास 5 या उससे कम है! जोड़े --no-run-if-emptyको xargsमें के रूप में (ls -t|head -n 5;ls)|sort|uniq -u|xargs --no-run-if-empty rmकृपया जवाब अद्यतन करें।
गोन्फी डेन Tschal

3
यहां तक ​​कि "रिक्त स्थान वाले नामों का समर्थन करता है" यहां तक ​​कि खतरनाक है। एक नाम पर विचार करें जिसमें शाब्दिक उद्धरण शामिल हैं: touch 'foo " bar'कमांड के पूरे बाकी को फेंक देगा।
चार्ल्स डफी

2
... यह xargs -d $'\n'आपकी सामग्री में उद्धरण इंजेक्षन करने की तुलना में उपयोग करने के लिए सुरक्षित है, हालांकि इनपुट स्ट्रीम (जो वास्तव में सही lsकरने के अलावा कुछ का उपयोग करने की आवश्यकता है) को NUL-delimiting करना आदर्श विकल्प है।
चार्ल्स डफी

59

सलदज के उत्तर का सरल संस्करण:

ls -tr | head -n -5 | xargs --no-run-if-empty rm 

ls -tr सभी फाइलों को प्रदर्शित करता है, सबसे पुराना पहला (-t नवीनतम पहले, -आर रिवर्स)।

हेड -5 एन सभी 5 लेकिन अंतिम लाइनों (यानी 5 सबसे नई फाइलें) को प्रदर्शित करता है।

xargs rm प्रत्येक चयनित फ़ाइल के लिए rm कॉल करता है।


15
Xargs में --no-run-if- खाली जोड़ने की आवश्यकता है ताकि 5 से कम फ़ाइलों के होने पर यह विफल न हो।
टॉम

ls -1tr | सिर -n -5 | xargs rm <---------- आपको एक -1 को ls में जोड़ने की आवश्यकता है या आपको ठीक से काम करने के लिए सिर के लिए सूची आउटपुट नहीं मिलेगा
Al Joslin

3
@AlJoslin, -1डिफ़ॉल्ट है जब आउटपुट एक पाइपलाइन के लिए है, तो यह यहाँ अनिवार्य नहीं है। इसमें बहुत बड़े मुद्दे हैं, xargsजब रिक्त स्थान के नाम, उद्धरण और सी के साथ नामों के डिफ़ॉल्ट व्यवहार से संबंधित है ।
चार्ल्स डफी

ऐसा लगता है कि --no-run-if-emptyमेरे खोल में मान्यता प्राप्त नहीं है। मैं खिड़कियों पर Cmder का उपयोग कर रहा हूं।
स्टेफुलिश

-0अगर फ़ाइलनाम में व्हॉट्सएप हो सकता है, तो विकल्प का उपयोग करने की आवश्यकता हो सकती है। हालांकि अभी तक इसका परीक्षण नहीं किया गया है। स्रोत
कीथ

18
find . -maxdepth 1 -type f -printf '%T@ %p\0' | sort -r -z -n | awk 'BEGIN { RS="\0"; ORS="\0"; FS="" } NR > 5 { sub("^[0-9]*(.[0-9]*)? ", ""); print }' | xargs -0 rm -f

GNU को -ff के लिए GNU खोजने की आवश्यकता है, और -U के लिए GNU सॉर्ट करें, और -0 के लिए GNU awk, और -0 के लिए GNU xargs, लेकिन एम्बेडेड newlines या रिक्त स्थान वाली फ़ाइलों को संभालता है।


2
यदि आप निर्देशिकाओं को हटाना चाहते हैं, तो -f को a -d में बदलें और rr में a -r जोड़ें। खोजो। -Maxdepth 1 -टाइप d -printf '% T @% p \ 0' | sort -r -z -n | awk 'BEGIN {RS = "\ 0"; ओआरएस = "\ 0"; FS = ""} NR> 5 {उप ("^ [0-9] * (! [0-9] *)?", ""); प्रिंट} ’| xargs -0 rm -rf
एलेक्स

1
एक नज़र में, मैं awkतर्क की जटिलता (या, उस बात के लिए, आवश्यकता) पर हैरान हूं । क्या मुझे ओपी के प्रश्न के अंदर कुछ आवश्यकताएं याद आ रही हैं जो इसे आवश्यक बनाती हैं?
चार्ल्स डफी

@Charles डफी: उप () टाइमस्टैम्प को हटाता है, जो कि सॉर्ट किया जाता है। "% T @" द्वारा निर्मित टाइमस्टैम्प में एक अंश भाग शामिल हो सकता है। एफएस के साथ अंतरिक्ष पर विभाजन एम्बेडेड रिक्त स्थान के साथ पथ को तोड़ता है। मुझे लगता है कि पहले अंतरिक्ष कार्यों के माध्यम से हटाने, लेकिन लगभग पढ़ने में मुश्किल है। RS और ORS विभाजक को कमांड लाइन पर सेट नहीं किया जा सकता है, क्योंकि वे NUL हैं।
21

1
@ इस प्रकार, मेरा सामान्य दृष्टिकोण शेल while read -r -d ' '; IFS= -r -d ''; do ...लूप में पाइप करना है - पहला रीड स्पेस पर समाप्त होता है, जबकि दूसरा एनयूएल पर जाता है।
चार्ल्स डफी

@Charles डफी: मैं हमेशा कच्चे खोल की लेयर करता हूं, शायद बाइजेंटाइन के कारण चिंताओं का हवाला देते हुए। मुझे अब लगता है कि GNU sed -z -e 's/[^ ]* //; 1,5d'सबसे स्पष्ट है। (या शायद sed -n -z -e 's/[^ ]* //; 6,$p'
2

14

वर्तमान निर्देशिका में निर्देशिका होने पर ये सभी उत्तर विफल हो जाते हैं। यहाँ कुछ है जो काम करता है:

find . -maxdepth 1 -type f | xargs -x ls -t | awk 'NR>5' | xargs -L1 rm

यह:

  1. वर्तमान निर्देशिका में निर्देशिका होने पर काम करता है

  2. प्रत्येक फ़ाइल को हटाने की कोशिश करता है भले ही पिछले एक को हटाया नहीं जा सकता है (अनुमतियों, आदि के कारण)

  3. वर्तमान निर्देशिका में फ़ाइलों की संख्या अत्यधिक होने पर सुरक्षित रूप से विफल हो जाता है और xargsसामान्य रूप से आपके ऊपर ()-x )

  4. फ़ाइल नाम में रिक्त स्थान की पूर्ति नहीं करता है (शायद आप गलत OS का उपयोग कर रहे हैं?)


5
यदि findएक से अधिक फाइलनामों को एक कमांड लाइन पर पारित किया जा सकता है तो क्या होता है ls -t? (संकेत: आपको ऐसे कई रन मिलते हैं ls -t, जिनमें से प्रत्येक को केवल व्यक्तिगत रूप से क्रमबद्ध किया जाता है, न कि विश्व स्तर पर सही क्रम के क्रम में; इस प्रकार, यह उत्तर पर्याप्त रूप से बड़ी निर्देशिकाओं के साथ चलने पर बुरी तरह से टूट जाता है)।
चार्ल्स डफी

12
ls -tQ | tail -n+4 | xargs rm

प्रत्येक फ़ाइल नाम का हवाला देते हुए, संशोधन समय द्वारा फ़ाइल नाम सूचीबद्ध करें। पहले 3 (3 सबसे हाल के) को छोड़ दें। शेष निकालें।

EDIT की मदद से टिप्पणी के बाद mklement0 (धन्यवाद!): सही -n + 3 तर्क, और ध्यान दें कि यह अपेक्षा के अनुरूप काम नहीं करेगा यदि फ़ाइल नाम में नई सीमाएँ और / या निर्देशिका में उपनिर्देशिकाएँ हों।


-Qविकल्प मेरी मशीन पर मौजूद प्रतीत नहीं होता है।
पियरे-एड्रियन ब्यूसन

4
हम्म, विकल्प GNU कोर के बर्तनों में ~ 20 साल से है, लेकिन बीएसडी वेरिएंट में इसका उल्लेख नहीं किया गया है। क्या आप एक मैक पर हैं?
मार्क

हाँ मैं हुँ। नहीं सोचा था कि अप-टू-डेट सिस्टम के बीच वास्तव में इस तरह की बुनियादी आज्ञाओं के लिए मतभेद थे। आपके उत्तर के लिए धन्यवाद !
पियरे-एड्रियन ब्यूसन

3
@ मर्क: ++ के लिए -Q। हां, -Qएक GNU एक्सटेंशन है (यहां देखें) POSIX lsकल्पना है )। एक छोटा सा चेतावनी (शायद ही कभी अभ्यास में एक समस्या): फिल्म्स में शाब्दिक के रूप में -Qएम्बेडेड नई लाइनों को एनकोड करता है \n, जो rmपहचान नहीं करेगा। पहले 3 को बाहर करने के लिए , xargsतर्क होना चाहिए +4। अंत में, एक चेतावनी जो अधिकांश अन्य उत्तरों पर भी लागू होती है: आपकी कमांड केवल उसी उद्देश्य के रूप में काम करेगी यदि वर्तमान डायर में कोई उपनिर्देशिका नहीं है ।
mklement0

1
जब हटाने के लिए कुछ भी नहीं है, तो आपके पास --no-run-if-emptyविकल्प के साथ कॉल ls -tQ | tail -n+4 | xargs --no-run-if-empty rm
ज़ार है

8

नई कहानियों को अनदेखा करना सुरक्षा और अच्छे कोडिंग की अनदेखी है। wnoise का एक ही अच्छा जवाब था। यहाँ उसकी भिन्नता है जो फ़ाइल नाम को एक सरणी $ x में रखता है

while IFS= read -rd ''; do 
    x+=("${REPLY#* }"); 
done < <(find . -maxdepth 1 -printf '%T@ %p\0' | sort -r -z -n )

2
मैं क्लीयर करने का सुझाव देता हूं IFS- अन्यथा आप फ़ाइल नाम से व्हाट्सएप को खोने का जोखिम उठाते हैं। पढ़ने की आज्ञा के लिए गुंजाइश कर सकते हैं:while IFS= read -rd ''; do
चार्ल्स डफी

1
क्यों "${REPLY#* }"?
msciwoj

4

यदि फ़ाइलनाम में स्थान नहीं हैं, तो यह काम करेगा:

ls -C1 -t| awk 'NR>5'|xargs rm

यदि फ़ाइलनाम में स्थान हैं, तो कुछ ऐसा है

ls -C1 -t | awk 'NR>5' | sed -e "s/^/rm '/" -e "s/$/'/" | sh

मूल तर्क:

  • समय-क्रम, एक कॉलम में फाइलों की एक सूची प्राप्त करें
  • सभी प्राप्त करें लेकिन इस उदाहरण के लिए पहले 5 (n = 5)
  • पहला संस्करण: उन्हें rm भेजें
  • दूसरा संस्करण: जीन एक स्क्रिप्ट जो उन्हें ठीक से हटा देगा

while readरिक्त स्थान से निपटने के लिए चाल मत भूलना : ls -C1 -t | awk 'NR>5' | while read d ; do rm -rvf "$d" ; done
गुलाबी

1
@pinkeen, वहाँ दिए गए के रूप में काफी सुरक्षित नहीं है। while IFS= read -r dथोड़ा बेहतर होगा - -rबैकस्लैश शाब्दिक रूप से खपत होने से रोकता है read, और IFS=अनुगामी व्हिटस के स्वचालित ट्रिमिंग को रोकता है।
चार्ल्स डफी

4
BTW, अगर कोई शत्रुतापूर्ण फाइलनाम के बारे में चिंतित है, तो यह एक अत्यंत खतरनाक दृष्टिकोण है। के साथ बनाई गई फ़ाइल पर विचार करें touch $'hello \'$(rm -rf ~)\' world'; फ़ाइल नाम के अंदर शाब्दिक उद्धरण आपके द्वारा जोड़े जा रहे शाब्दिक उद्धरणों का मुकाबला करेगा sed, जिसके परिणामस्वरूप फ़ाइलनाम निष्पादित किया जाएगा।
चार्ल्स डफी

1
(स्पष्ट होने के लिए, ऊपर "यह" रूप का उल्लेख था | sh, जो शेल इंजेक्शन भेद्यता के साथ एक है)।
चार्ल्स डफी

2

ज़श के साथ

यह मानते हुए कि आप वर्तमान निर्देशिकाओं की परवाह नहीं करते हैं और आपके पास 999 से अधिक फाइलें नहीं होंगी (यदि आप चाहते हैं तो एक बड़ी संख्या चुनें, या थोड़ी सी लूप बनाएं)।

[ 6 -le `ls *(.)|wc -l` ] && rm *(.om[6,999])

में *(.om[6,999]), .फ़ाइलों का मतलब है, oक्रमबद्ध क्रमबद्ध तरीके, mसंशोधन की तारीख के माध्यम से साधन ( aएक्सेस समय या cइनोड परिवर्तन के लिए डाल ), [6,999]फ़ाइल की एक सीमा चुनता है, इसलिए पहले 5 rm नहीं करता है।


गहन, लेकिन मेरे जीवन के लिए मुझे omकाम करने के लिए छंटनी करने योग्य ग्लोब क्वालीफायर ( ) नहीं मिल सकता है ( मैंने जो भी छांटने की कोशिश की है उसका कोई प्रभाव नहीं है - न ही OSX 10.11.2 पर (zsh 5.0.8 और 5.1.1 के साथ प्रयास किया गया) , और न ही Ubuntu 14.04 (zsh 5.0.2) पर - मैं क्या याद कर रहा हूँ ?. रेंज एंडपॉइंट के लिए: इसे हार्ड-कोड करने की आवश्यकता नहीं है, बस -1अंतिम प्रविष्टि को संदर्भित करने के लिए उपयोग करें और इस प्रकार सभी शेष फाइलें शामिल हैं [6,-1]:।
mklement0

2

मुझे लगता है कि यह एक पुराना धागा है, लेकिन शायद किसी को इससे फायदा होगा। इस कमांड को वर्तमान निर्देशिका में फाइलें मिलेंगी:

for F in $(find . -maxdepth 1 -type f -name "*_srv_logs_*.tar.gz" -printf '%T@ %p\n' | sort -r -z -n | tail -n+5 | awk '{ print $2; }'); do rm $F; done

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

find . -maxdepth 1 -type f -name "*_srv_logs_*.tar.gz" -printf '%T@ %p\n'

इसके बाद, उन्हें टाइमस्टैम्प द्वारा सॉर्ट करें:

sort -r -z -n

फिर, सूची से 4 सबसे हाल की फ़ाइलों को बंद करें:

tail -n+5

दूसरा कॉलम पकड़ो (फ़ाइल नाम, टाइमस्टैम्प नहीं):

awk '{ print $2; }'

और फिर उस पूरी बात को बयान के लिए लपेट दें:

for F in $(); do rm $F; done

यह एक अधिक वर्बोज़ कमांड हो सकता है, लेकिन मुझे सशर्त फ़ाइलों को लक्षित करने और उनके खिलाफ अधिक जटिल आदेशों को निष्पादित करने में सक्षम होने के लिए बहुत बेहतर भाग्य था।


1

सैड-ओनलीयर्स में दिलचस्प सीएमडी पाया गया - पिछली 3 लाइनों को हटाएं - बिल्ली को त्वचा के लिए एक और तरीके से परिपूर्ण करें (ठीक नहीं) लेकिन विचार:

 #!/bin/bash
 # sed cmd chng #2 to value file wish to retain

 cd /opt/depot 

 ls -1 MyMintFiles*.zip > BigList
 sed -n -e :a -e '1,2!{P;N;D;};N;ba' BigList > DeList

 for i in `cat DeList` 
 do 
 echo "Deleted $i" 
 rm -f $i  
 #echo "File(s) gonzo " 
 #read junk 
 done 
 exit 0

1

सभी को हटाता है, लेकिन 10 नवीनतम (सबसे पुनरावर्ती) फाइलें

ls -t1 | head -n $(echo $(ls -1 | wc -l) - 10 | bc) | xargs rm

यदि 10 से कम फ़ाइलें नहीं हैं, तो कोई फ़ाइल नहीं निकाली गई है और आपके पास होगी: त्रुटि सिर: अवैध पंक्ति गणना - 0

बैश वाली फाइलों को गिनने के लिए


1

मुझे व्यस्त बॉक्स (राउटर) के लिए एक सुरुचिपूर्ण समाधान की आवश्यकता थी, सभी xargs या सरणी समाधान मेरे लिए बेकार थे - ऐसा कोई कमांड उपलब्ध नहीं है। खोज और माइम उचित जवाब नहीं है क्योंकि हम 10 वस्तुओं के बारे में बात कर रहे हैं और जरूरी नहीं कि 10 दिन हों। एस्पो का जवाब सबसे छोटा और सबसे साफ और सबसे अधिक संभावना वाला था।

रिक्त स्थान के साथ त्रुटि और जब कोई फ़ाइल नहीं हटाई जानी है, तो दोनों को बस मानक तरीके से हल किया गया है:

rm "$(ls -td *.tar | awk 'NR>7')" 2>&-

थोड़ा और अधिक शैक्षिक संस्करण: हम यह सब कर सकते हैं यदि हम अलग-अलग awk का उपयोग करते हैं। आम तौर पर, मैं इस पद्धति का उपयोग awk से sh तक (वापसी) चर को पास करने के लिए करता हूं। जैसा कि हम हर समय पढ़ते हैं जो नहीं किया जा सकता है, मैं अलग होने की भीख माँगता हूँ: यहाँ विधि है।

फ़ाइल नाम में रिक्त स्थान के बारे में कोई समस्या नहीं के साथ .tar फ़ाइलों के लिए उदाहरण। परीक्षण करने के लिए, "आरएमएस" को "एलएस" से बदलें।

eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')

स्पष्टीकरण:

ls -td *.tarसभी .tar फ़ाइलों को समय के अनुसार क्रमबद्ध करता है। वर्तमान फ़ोल्डर में सभी फ़ाइलों पर लागू करने के लिए, "d * .tar" भाग को हटा दें

awk 'NR>7... पहले 7 लाइनों को छोड़ देता है

print "rm \"" $0 "\"" एक लाइन का निर्माण करता है: rm "फ़ाइल का नाम"

eval इसे निष्पादित करता है

चूंकि हम उपयोग कर रहे हैं rm, इसलिए मैं उपरोक्त कमांड का उपयोग स्क्रिप्ट में नहीं करूंगा! समझदार उपयोग है:

(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))

ls -tआदेश का उपयोग करने के मामले में इस तरह के मूर्खतापूर्ण उदाहरणों पर कोई नुकसान नहीं होगा: touch 'foo " bar'औरtouch 'hello * world' । ऐसा नहीं है कि हम कभी वास्तविक जीवन में ऐसे नामों के साथ फाइल बनाते हैं!

पक्षीय लेख। यदि हम इस तरह से एक चर को पास करना चाहते हैं, तो हम बस प्रिंट को संशोधित करेंगे (सरल रूप, कोई रिक्त स्थान बर्दाश्त नहीं):

print "VarName="$1

VarNameके मान को चर सेट करने के लिए $1। एक बार में कई चर बनाए जा सकते हैं। यह VarNameएक सामान्य श वेरिएबल बन जाता है और सामान्य रूप से बाद में स्क्रिप्ट या शेल में उपयोग किया जा सकता है। इसलिए, awk के साथ वैरिएबल बनाने और उन्हें शेल में वापस देने के लिए:

eval $(ls -td *.tar | awk 'NR>7 { print "VarName=\""$1"\""  }'); echo "$VarName"

0
leaveCount=5
fileCount=$(ls -1 *.log | wc -l)
tailCount=$((fileCount - leaveCount))

# avoid negative tail argument
[[ $tailCount < 0 ]] && tailCount=0

ls -t *.log | tail -$tailCount | xargs rm -f

2
xargsबिना -0या कम -d $'\n'से कम न्यूनतम अविश्वसनीय है; निरीक्षण करें कि यह फ़ाइल के साथ रिक्त स्थान के साथ कैसे व्यवहार करता है या इसके नाम के पात्रों का उद्धरण करता है।
चार्ल्स डफी

0

मैंने इसे बैश शेल स्क्रिप्ट में बनाया है। उपयोग: keep NUM DIRजहां NUM फ़ाइलों को रखने की संख्या है और DIR स्क्रब करने के लिए निर्देशिका है।

#!/bin/bash
# Keep last N files by date.
# Usage: keep NUMBER DIRECTORY
echo ""
if [ $# -lt 2 ]; then
    echo "Usage: $0 NUMFILES DIR"
    echo "Keep last N newest files."
    exit 1
fi
if [ ! -e $2 ]; then
    echo "ERROR: directory '$1' does not exist"
    exit 1
fi
if [ ! -d $2 ]; then
    echo "ERROR: '$1' is not a directory"
    exit 1
fi
pushd $2 > /dev/null
ls -tp | grep -v '/' | tail -n +"$1" | xargs -I {} rm -- {}
popd > /dev/null
echo "Done. Kept $1 most recent files in $2."
ls $2|wc -l
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.