एक्स लाइनों से कम फ़ाइलों को हटाने का तेज़ तरीका


10

क्या एक तेज और बहुत जटिल तरीका नहीं है कि निर्देशिका में सभी फ़ाइलों को हटाने के लिए जो x लाइनों के तहत लंबे समय तक, बैश में हैं?

जवाबों:


10

यहाँ एक POSIX समाधान है जिसे समझने के लिए बहुत सरल होना चाहिए:

find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;

स्टीफन के जवाब के रूप में , echoजब हटा दिया जाएगा के साथ खुश को हटा दें।


स्पष्टीकरण, यूनिक्स / लिनक्स के लिए पूरी तरह से नए लोगों के लिए लिखा गया है:

डॉट .वर्तमान निर्देशिका का प्रतिनिधित्व करता है। findफ़ाइलों और निर्देशिकाओं को पुनरावर्ती पाता है ., और उनके साथ काम कर सकता है।

-typeमें से एक है findके प्राइमरी ; यह एक परीक्षण है जो प्रत्येक फ़ाइल और निर्देशिका के लिए किया जाएगा जो पुनरावर्ती रूप से (भीतर .) पाया जाता है , और लाइन पर बाकी प्राइमरी का मूल्यांकन केवल तभी किया जाता है यदि यह "सही" है।

इस विशेष मामले में, हम केवल तभी जारी रखते हैं जब हम एक नियमित फ़ाइल के साथ काम कर रहे होते हैं , न कि कोई निर्देशिका या कुछ और (जैसे एक ब्लॉक डिवाइस।)।


-execप्राथमिक (के find) एक बाहरी आदेश कहता है, और उसे अगले प्राथमिक के लिए आगे बढ़ता है, तो बाहरी कमांड बाहर निकलता है सफलतापूर्वक ( "0" के निकास की स्थिति)। {}फ़ाइल नाम से "माना" किया जा रहा साथ बदल दिया है findआदेश। इसलिए पहली -execकॉल निम्न शेल कमांड के बराबर है, जिसे बदले में प्रत्येक फ़ाइल के लिए निष्पादित किया गया है:

awk -v x=10 'NR==x{exit 1}' ./somefilename

Awk अपने आप में एक संपूर्ण भाषा है, जिसे CSV जैसी सीमांकित पाठ फ़ाइलों को संभालने के लिए डिज़ाइन किया गया है। Awk सशर्तियां और आदेश (जो एकल उद्धरणों के बीच और अक्षरों से शुरू NRहोते हैं) को पाठ फ़ाइल की प्रत्येक पंक्ति के लिए निष्पादित किया जाता है। (स्पष्ट लूपिंग।)

Awk को पूरी तरह से जानने के लिए, मैं Grymoire Tutorial की सिफारिश करता हूं , लेकिन मैं ऊपर दिए गए कमांड में इस्तेमाल किए गए Awk फीचर्स के बारे में बताऊंगा


-vAwk करने के लिए ध्वज हमारे सामने Awk आदेश (फ़ाइल की प्रत्येक पंक्ति के लिए।) क्रियान्वित कर रहे हैं इस मामले में हम सेट में एक Awk चर (एक बार) स्थापित करने के लिए अनुमति देता है xके लिए 10


NRएक विशेष अर्क चर है जिसका उल्लेख " वर्तमान आर इकोर्ड के एन umber " है। दूसरे शब्दों में, यह वह पंक्ति संख्या है जिसे हम लूप के माध्यम से किसी विशेष पास में देख रहे हैं।

(ध्यान दें कि यह है संभव है, हालांकि असामान्य, एक अलग "का उपयोग करने आर ecord एस , eparator" एक नई पंक्ति चरित्र के डिफ़ॉल्ट से सेटिंग से RSयहाँ रिकॉर्ड विभाजक के साथ खेल का एक उदाहरण है। )


सामान्य रूप से स्थितियाँ ( कार्य घुंघराले ब्रेसिज़ के बाहर) (समान रूप से ब्रेसिज़ के अंदर ) में अवाक स्क्रिप्ट्स होती हैं। यौगिक स्थितियाँ और यौगिक क्रियाएं हो सकती हैं, और एक डिफ़ॉल्ट स्थिति (सत्य) और एक डिफ़ॉल्ट क्रिया (प्रिंट) होती है, लेकिन हमें इसकी आवश्यकता है 'उन लोगों के साथ परेशान नहीं है।

यहां शर्त है, "क्या यह 10 वीं पंक्ति है?" यदि यह मामला है, तो हम एक गैर-शून्य निकास स्थिति के साथ बाहर निकलते हैं, जो शेल स्क्रिप्टिंग में "असफल कमांड समाप्ति" का अर्थ है।

इस प्रकार यह एकमात्र आदेश सफलतापूर्वक बाहर निकल जाएगा यदि फ़ाइल का अंत 10 वीं पंक्ति तक पहुंचने से पहले पहुंच जाता है।

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


अगली -execकॉल (यदि आप हटाते हैं echo) प्रत्येक फ़ाइल (जो कि findप्राइमरी के मूल्यांकन में उस तक जाती है) को हटाकर हटा देगी :

rm -f ./somefilename

5

एक findकार्यान्वयन मान लें जो -readableविधेय का समर्थन करता है (यदि आपका findसमर्थन नहीं करता है, तो बस इसे हटा दें, आपको बस गैर-पठनीय फ़ाइलों के लिए त्रुटि संदेश मिलेगा, या इसके साथ प्रतिस्थापित करें -exec test -r {} \;):

x=10 find . -type f -readable -exec sh -c '
  for file do
    lines=$(wc -l < "$file") && [ "$((lines))" -lt "$x" ] && echo rm -f "$file"
  done' sh {} +

echoअगर खुश है तो निकाल दो ।

यह विशेष रूप से कुशल नहीं है कि यह हर फ़ाइल में सभी पंक्तियों को गिनता है जबकि इसे केवल xवें एक पर रोकने की आवश्यकता होती है और यह प्रत्येक फ़ाइल के लिए एक wc(और संभवतः एक rm) कमांड चलाता है ।

GNU के साथ awk, आप इसे और अधिक कुशल बना सकते हैं:

x=10
find . -type f -readable -exec awk -v x="$x" -v ORS='\0' '
  FNR == x {nextfile}
  ENDFILE {if (FNR < x) print FILENAME}' {} +|
  xargs -r0 echo rm -f

(फिर, echoखुश होने पर हटा दें )।

उसी के साथ perl:

x=10 find . -type f -readable -exec perl -Tlne '
  if ($. == $ENV{x}) {close ARGV}
  elsif (eof) {print $ARGV; close ARGV}' {} +

बदलें printके साथ unlinkखुश हैं।


1. आखिर किसलिए sh? 2. wc -l < "$file"से तेज है wc -l "$file"? 3. श का मूल्य कैसे पता चलता है $x, जिसे कॉल बैश शेल में परिभाषित किया गया है?

3
@tomas, अंतिम shवह है जो उस इनलाइन स्क्रिप्ट में जाता है $0, उदाहरण के लिए त्रुटि संदेशों के लिए उपयोग किया जाता है। wc -l "$file"फ़ाइल का नाम जो हम यहां नहीं चाहते हैं और प्रिंट करेंगे wcभले ही फ़ाइल को खोला न जा सके। $xको निर्यात किया जाता है find( x=10 find...) जो खुद इसे पास करता है sh
स्टीफन चेज़लस

धन्यवाद! लेकिन मैं इस त्रुटि का अनुमान लगाता हूं जो मुझे OSX पर मिलता है इसका मतलब यह है कि मेरा बैश संस्करण -अस्थायी ध्वज का समर्थन नहीं करता है? find: -readable: unknown primary or operator
मृत्युंजय

1
@ दुर्रुट्टी, यह नीचे नहीं है bashbashकेवल एक कमांड-लाइन दुभाषिया है, लेकिन findकार्यान्वयन का। -readableएक GNU एक्सटेंशन है, जो OS / X में उपलब्ध नहीं है find। इसका उपयोग केवल उन फ़ाइलों तक सीमित करने के लिए किया जाता है जो पठनीय हैं (आप गैर-पठनीय फ़ाइलों के लिए लाइन की गिनती प्राप्त करने में सक्षम नहीं होंगे)। आप इसे पहले एक के लिए छोड़ सकते हैं, फिर आप केवल wcपढ़ने योग्य फ़ाइलों के लिए फ़ाइलें खोलते समय त्रुटि संदेश प्राप्त कर सकते हैं।
स्टीफन चेज़लस

@ स्टीफनचेज़लस, यह जवाब इतना मुश्किल है कि मैं हैरान रह गया: क्या मुझे अपने जवाब के साथ कोई बढ़त के मामले याद आए? :)
वाइल्डकार्ड

2

पूर्णता के लिए, एक तरफ AWK आप एक ही परिणाम प्राप्त करने के लिए GNU sed का उपयोग कर सकते हैं:

find . -type f -exec sed 11q1 '{}' ';' -exec echo rm -f '{}' ';'

जिसके परिणामस्वरूप थोड़ी अधिक संक्षिप्त कमांड लाइन होती है।

व्याख्या

11 - is the address, i.e. "the eleventh line"
q - is for _q_uit (abort the execution)
1 - is the exit code parameter for q (GNU sed extension) 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.