2012-07-03 31 views
67

क्या कोई बैश कमांड है जो पैटर्न की मेल खाने वाली फ़ाइलों की संख्या को गिना जाता है?क्या कोई बैश कमांड है जो फाइलों की गणना करता है?

उदाहरण के लिए, मैं एक निर्देशिका में सभी फ़ाइलों को जो इस आकार से मिलान की गिनती प्राप्त करना चाहते हैं: log*

उत्तर

83

यह सरल एक लाइनर किसी भी खोल में काम करना चाहिए, सिर्फ पार्टी नहीं:

ls -1q log* | wc -l 

ls -1q आप फ़ाइल प्रति एक लाइन दे देंगे, भले ही वे इस तरह के नई-पंक्तियों के रूप में खाली स्थान या विशेष वर्ण।

उत्पादन wc -l पर पाइप किया गया है, जो लाइनों की संख्या की गणना करता है।

+0

आपके पास अभी * विपरीत तरफ है लेकिन यह thx बहुत काम करता है – hudi

+0

धन्यवाद, आपके प्रश्न से मेल खाने के लिए सही। :) – Daniel

+5

मैं '-l' का उपयोग नहीं करता, क्योंकि प्रत्येक फ़ाइल पर 'stat (2)' की आवश्यकता होती है और गिनती के प्रयोजनों के लिए कुछ भी नहीं जोड़ता है। – camh

27

इस प्रयास करें:

echo *.log | wc -w 

या एक पुनरावर्ती खोज के लिए :

find . -type f -name '*.log' | wc -l 

wc -w आउटपुट में शब्दों की संख्या की गणना करता है (बैश उस पैटर्न से मेल खाने वाली फ़ाइलों की एक स्पेस से अलग सूची के रूप में *.log का विस्तार करेगा), जबकि wc -l लाइनों की संख्या (find प्रिंट प्रति पंक्ति एक परिणाम) की गणना करेगा।


अद्यतन: एक गैर पुनरावर्ती खोज के लिए, ऐसा करते हैं:

find . -maxdepth 1 -type f -name '*.log' | wc -l 

यह अंतरिक्ष समस्या lanzz ने उल्लेख किया धोखा देगा।

+3

'echo * .log | wc -w' गलत परिणाम देगा यदि कुछ फ़ाइलों के नाम उनके स्थान पर हैं – lanzz

+0

@lanzz: True; उस बारे में सोचा नहीं था! –

+0

मैंने रिक्त स्थान – hudi

32

आप बैश के साथ सुरक्षित रूप से कर सकते हैं (यानी या रिक्त स्थान के साथ फ़ाइलें द्वारा bugged नहीं किया जाएगा उनके नाम में \n):

$ shopt -s nullglob 
$ logfiles=(*.log) 
$ echo ${#logfiles[@]} 
$ shopt -u nullglob 

आप nullglob इतना सक्षम करने के लिए है कि आप शाब्दिक नहीं मिलता है जरूरत *.log$logfilesarray में कोई फ़ाइल नहीं मिलती है।

1
ls -1 log* | wc -l 

सूची पैरामीटर लाइनों गिनती का उपयोग करने जा के साथ शब्द गणना आदेश के लिए प्रत्येक पंक्ति में एक फ़ाइल और फिर इसे पाइप इसका मतलब है।

+0

"-1" विकल्प आवश्यक नहीं है। लेकिन यदि कोई फ़ाइल पैटर्न से मेल नहीं खाती है तो आप ls त्रुटि संदेश को छिपाना चाहेंगे। मैं सुझाव देता हूं "एलएस लॉग * 2>/dev/null | wc -l"। – JohnMudd

3

यदि आपके पास बहुत सी फाइलें हैं और आप सुरुचिपूर्ण shopt -s nullglob और बैश सरणी समाधान का उपयोग नहीं करना चाहते हैं, तो आप फ़ाइल का नाम मुद्रित नहीं करते हैं, जब तक आप फ़ाइल का नाम प्रिंट नहीं करते हैं नई पंक्तियां)।

find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l 

इसमें सभी फ़ाइलें कि मैच लॉग * और उस .* के साथ शुरू नहीं है मिलेगा - "का नाम नहीं *।" Redunant है, लेकिन यह ध्यान रखें कि "ls" के लिए डिफ़ॉल्ट नहीं है महत्वपूर्ण है डॉट-फाइलें दिखाएं, लेकिन खोज के लिए डिफ़ॉल्ट उन्हें शामिल करना है।

यह एक सही उत्तर है, और किसी भी प्रकार का फ़ाइल नाम संभाल सकता है जिसे आप फेंक सकते हैं, क्योंकि फ़ाइल नाम कमांड के बीच कभी नहीं पारित होता है।

लेकिन, shopt nullglob उत्तर सबसे अच्छा जवाब है!

+0

आपको शायद फिर से जवाब देने के बजाय अपना मूल उत्तर अपडेट करना चाहिए। – qodeninja

+0

मुझे लगता है कि 'ls' का उपयोग कर 'ढूंढ' बनाम समस्या का समाधान करने के दो अलग-अलग तरीके हैं। 'find' हमेशा मशीन पर मौजूद नहीं होता है, लेकिन आमतौर पर 'ls' है, – mogsie

5

इस प्रश्न का स्वीकार्य उत्तर गलत है, लेकिन मेरे पास कम प्रतिनिधि है इसलिए इसमें कोई टिप्पणी नहीं मिल सकती है।

इस सवाल का सही जवाब चटाई द्वारा दिया जाता है:

shopt -s nullglob 
logfiles=(*.log) 
echo ${#logfiles[@]} 

स्वीकार किए जाते हैं जवाब के साथ समस्या यह है कि WC -l मायने रखता है newline वर्णों की संख्या है, और उन्हें गिना जाता है, भले ही वे टर्मिनल के लिए प्रिंट जैसा '?' 'ls -l' के आउटपुट में। इसका मतलब है कि स्वीकार्य उत्तर विफल होता है जब फ़ाइल नाम में एक न्यूलाइन वर्ण होता है। मैं सुझाव दिया आदेश का परीक्षण किया है:

ls -l log* | wc -l 

और यह ग़लती से 2 का मान है, भले ही वहाँ केवल 1 पैटर्न जिसका नाम एक नई पंक्ति वर्ण होना करने के लिए होता मिलान फ़ाइल की रिपोर्ट। उदाहरण के लिए:

touch log$'\n'def 
ls log* -l | wc -l 
17

यहाँ जवाब में से बहुत सारे हैं, लेकिन कुछ

  • फ़ाइल नाम है कि हाइफ़न के साथ शुरू उन में रिक्त स्थान, नई-पंक्तियों, या नियंत्रण पात्रों के साथ

    • फ़ाइल नाम को ध्यान में रखना नहीं है (-l नामक एक फ़ाइल की कल्पना करें)
    • खाली निर्देशिकाएं (यानी परिणाम 0 है)
    • अत्यधिक बड़ी निर्देशिकाएं (उन्हें सूचीबद्ध करने से सभी स्मृति समाप्त हो सकती हैं)

    यहाँ एक समाधान है कि उन सभी को संभालती है:

    ls 2>/dev/null -Ub1 -- log* | wc -l 
    

    स्पष्टीकरण:

    • -Uls का कारण बनता है प्रविष्टियों को क्रमबद्ध नहीं करने के लिए, जिसका अर्थ यह पूरी निर्देशिका लोड करने के लिए की जरूरत नहीं है मेमोरी में लिस्टिंग
    • -b प्रिंट सी-शैली नोंग्राफिक वर्णों के लिए निकलती है, महत्वपूर्ण रूप से न्यूलाइन कोके रूप में मुद्रित करने का कारण बनता है।
    • 2>/dev/null stderr को रीडायरेक्ट करता है ताकि अगर 0 लॉग फाइलें हों, तो त्रुटि संदेश को अनदेखा करें। (ध्यान दें कि shopt -s nullglob इसके बजाय पूरी कार्य निर्देशिका को सूचीबद्ध करने के लिए ls का कारण बन जाएगा।)
    • wc -l निर्देशिका सूची को उत्पन्न होने के कारण उपभोग करता है, इसलिए ls का आउटपुट कभी भी किसी भी समय स्मृति में नहीं होता है।
    • -- फ़ाइल नाम (मामले log* में निकाल दिया जाता है) आदेश -- इतनी के रूप में ls को तर्क के रूप में समझा जा नहीं का उपयोग करने से अलग होती है

    खोल फाइलों की पूर्ण सूची से log* का विस्तार होगा, अगर यह फ़ाइलों का एक बहुत कुछ है, तो उसके बाद ग्रेप के माध्यम से यह चल रहा स्मृति समाप्त हो सकती है जो बेहतर हो जाता है: के

    ls -Ub1 | grep ^log | wc -l 
    

    यह पिछले एक संभालती है बहुत बड़ी निर्देशिका बहुत सारी मेमोरी का उपयोग किये बिना फाइलें (हालांकि यह सबशेल का उपयोग करती है)।

  • +1

    ग्रेट उत्तर और बेहद सटीक। – raratiru

    2

    इसके लिए मेरा एक लाइनर यहां है।

    file_count=$(shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)