एक निर्देशिका में फ़ाइलों की गिनती के लिए wc करने के लिए पाइपिंग के लिए एक अधिक उपयुक्त विकल्प है


12

यदि मैं करता हूं ls -1 target_dir | wc -l, तो मुझे एक निर्देशिका में फ़ाइलों की गिनती मिलती है। मुझे यह थोड़ा बोझिल लगता है। वहाँ एक और अधिक सुंदर या रसीला तरीका है?


2
आपको "-1" की आवश्यकता नहीं है जब wc पर पाइपिंग करें।
स्टीव

lsपहले से ही कुल गिनती देता है, तो कैसे के बारे में ls -l | head -1? यदि आप कुछ छोटा चाहते हैं तो इसे एक उपनाम बनाएं।
डैनियल वैगनर

2
@DanielWagner "कुल: nnn" आउटपुट ls -lफाइलों के कुल आकार को इंगित करता है, फाइलों की संख्या को नहीं।
डेविड रिचेर्बी

2
यह ध्यान रखें कि ls | wc -lयदि कोई फ़ाइल नाम newlines है तो आपको गलत गणना देगा।
चेपनर

यह फ़ाइल-सिस्टम पर निर्भर करता है, और निर्देशिका में निर्देशिका + 2 की गणना करता है। उत्तर में 2 अतिरिक्त हैं (जैसा कि यह खुद को और इसके माता-पिता को गिनता है)। stat -c %h .के रूप में एक ही जानकारी देता हैls -ld . | cut -d" " -f 2
ctrl-alt-delor

जवाबों:


12

मान लें कि बैश 4+ (जो कि उबंटू का कोई समर्थित संस्करण है):

num_files() (
    shopt -s nullglob
    cd -P -- "${1-.}" || return
    set -- *
    echo "$#"
)

यह के रूप में कॉल num_files [dir]dirवैकल्पिक है, अन्यथा यह वर्तमान निर्देशिका का उपयोग करता है। आपका मूल संस्करण छिपी हुई फ़ाइलों की गणना नहीं करता है, इसलिए न तो ऐसा करता है। यदि आप चाहते हैं कि shopt -s dotglobपहले set -- *

आपका मूल उदाहरण न केवल नियमित फ़ाइलों, बल्कि निर्देशिकाओं और अन्य उपकरणों को भी गिनाता है - यदि आप वास्तव में केवल नियमित फाइलें चाहते हैं (नियमित फ़ाइलों के लिए सहानुभूति सहित), तो आपको उन्हें जांचने की आवश्यकता होगी:

num_files() (
    local count=0

    shopt -s nullglob
    cd -P -- "${1-.}" || return
    for file in *; do
        [[ -f $file ]] && let count++
    done
    echo "$count"
)

यदि आपके पास GNU है, तो ऐसा कुछ भी एक विकल्प है (ध्यान दें कि इसमें छिपी हुई फाइलें शामिल हैं, जो आपकी मूल कमांड ने नहीं किया है):

num_files() {
    find "${1-.}" -maxdepth 1 -type f -printf x | wc -c
}

(परिवर्तन -typeकरने के लिए -xtypeअगर आप भी नियमित रूप से फ़ाइलों को सिमलिंक गणना करना चाहते हैं)।


setबहुत सारी फाइलें होने पर असफल नहीं होंगे ? मुझे लगता है xargsकि सामान्य स्थिति में उस काम को करने के लिए आपको कुछ समन कोड का उपयोग करना पड़ सकता है ।
l0b0

1
इसके अलावा shopt -s dotglobअगर आप चाहते हैं कि फाइलों की .गिनती शुरू हो जाए
डिजिटल ट्रॉमा

1
@ l0b0 मुझे नहीं लगता कि setहम इन परिस्थितियों में विफल होंगे, क्योंकि हम वास्तव में नहीं कर रहे हैं exec। बुद्धि के लिए, मेरे सिस्टम पर, getconf ARG_MAX262144 की पैदावार होती है, लेकिन अगर मैं करता हूं test_arg_max() { set -- {1..262145}; echo $#; }; test_arg_max, तो यह खुशी से 262145 जवाब देता है।
कोजीरो

@DavidRicherby -maxdepthPOSIX नहीं है।
क्रिस डाउन

4
@MichaelMartinez स्पष्ट कोड लिखना सही कोड लिखने का विकल्प नहीं है।
क्रिस डाउन

3

f=(target_dir/*);echo ${#f[*]}

नाम में रिक्त स्थान, newlines, आदि के साथ फ़ाइल के लिए सही ढंग से काम करता है।


क्या आप कुछ संदर्भ प्रदान कर सकते हैं? क्या इसे बैश स्क्रिप्ट में जाना चाहिए?
कोडेकोवॉय

यह हो सकता है। आप इसे सीधे शेल में भी डाल सकते हैं। उस संस्करण ने मान लिया कि आप वर्तमान निर्देशिका चाहते थे; मैंने इसे संपादित किया है इसलिए यह आपके प्रश्न के करीब है। मूल रूप से यह डायरेक्टरी की सभी फाइलों से युक्त शेल ऐरे वेरिएबल बनाता है, फिर उस एरे की गिनती को प्रिंट करता है। किसी भी गोले में काम करना चाहिए - बैश, ksh, zsh, आदि - लेकिन शायद सादे श / राख / पानी का छींटा नहीं है।
एरोन डेविस

2

lsमल्टी-कॉलम केवल अगर यह एक टर्मिनल पर सीधे आउटपुट करता है, तो आप "-1" विकल्प को हटा सकते हैं, आप wc"-l" विकल्प को हटा सकते हैं , केवल पहले मूल्य (आलसी समाधान पढ़ें, कानूनी साक्ष्य के लिए उपयोग नहीं किया जा सकता है,) आपराधिक जांच, मिशन महत्वपूर्ण, सामरिक ऑप्स ..)।

ls target | wc 

5
यह नए नाम वाले फ़ाइलनामों के लिए विफल है।
l0b0

@ मैनमुअल आपको wcतुच्छ मामले में भी फ़ाइलों की संख्या प्राप्त करने के लिए अपने परिणाम को पार्स करने की आवश्यकता होगी , तो यह भी एक समाधान कैसे है?
l0b0

@ इम्मानुएल यह विफल हो सकता है अगर targetएक ग्लोब है जो विस्तारित होने पर, कुछ चीजें शामिल होती हैं जो हाइफ़न से शुरू होती हैं। उदाहरण के लिए, एक नई निर्देशिका बनाएं, इसमें जाएं और करें touch -- {1,2,3,-a}.txt && ls *|wc(एनबी: rm -- *.txtउन फ़ाइलों को हटाने के लिए उपयोग करें।)
डेविड रिचर्जी

क्या आपका मतलब था wc -l? अन्यथा आपको lsआउटपुट की न्यूलाइन, वर्ड और बाइट काउंट मिलते हैं । डेविड रिचेर्बी ने यही कहा है: आपको इसे फिर से पार्स करना होगा।
इरिक

@ अगर मैं wcकोई तर्क नहीं देता, तो आपको यह तर्क देने की आवश्यकता नहीं है कि यदि आपका मस्तिष्क जानता है कि पहला तर्क नया है।
इमैनुअल

2

यदि यह आपके बाद की सफलता है (उनके नाम, आदि में newlines के साथ फ़ाइलों से निपटने के दौरान सटीक शुद्धता के बजाय), तो मैं सिर्फ ("लाइन गणना") के wc -lलिए उपनाम देने की सलाह देता हूं lc:

$ alias lc='wc -l'
$ ls target_dir|lc

जैसा कि अन्य ने नोट किया है, आपको -1विकल्प की आवश्यकता नहीं है ls, क्योंकि यह स्वचालित है जब lsएक पाइप पर लिख रहा है। (जब तक आप lsहमेशा कॉलम मोड का उपयोग करने के लिए उपनाम नहीं देते हैं। मैंने देखा है कि पहले, लेकिन बहुत बार नहीं।)

एक lcउपनाम सामान्य रूप से काफी उपयोगी है, और इस प्रश्न के लिए, यदि आप "वर्तमान निर्देशिका की गिनती" मामले को देखते हैं, तो आप के ls|lcरूप में रसीला मिल सकता है।


2

अब तक हारून के पास केवल अपनी तुलना में अधिक सक्सेस है। आपके दृष्टिकोण का एक और अधिक सही संस्करण जैसा दिख सकता है:

ls -aR1q | grep -Ecv '^\./|/$|^$'

वह पुन: सभी फाइलों को सूचीबद्ध करता है - निर्देशिका नहीं - गैर-मुद्रण योग्य वर्णों को बदलने के लिए शेल ग्लब्स का उपयोग करके वर्तमान निर्देशिका के नीचे .dotfiles सहित प्रति पंक्ति। grep किसी भी मूल निर्देशिका लिस्टिंग या .. या * / या रिक्त लाइनों को फ़िल्टर करता है - इसलिए प्रति फ़ाइल केवल एक पंक्ति होनी चाहिए - जिसमें से grep आपके पास वापस आ जाए। यदि आप चाहते हैं कि बाल निर्देशिकाएं भी शामिल हों:

ls -aR1q | grep -Ecv '^\.{1,2}/|^$'

-Rया तो मामले में निकालें यदि आप पुनरावर्ती परिणाम नहीं चाहते हैं।


1
मैं उस तरह की बात करना पसंद करता हूं find। यदि आप केवल एक गिनती चाहते हैं, तो यह काम करना चाहिए: find -mindepth 1 -maxdepth 1 -printf '\n'|wc -l(पुनरावर्ती परिणाम प्राप्त करने के लिए गहराई नियंत्रण हटा दें)।
आरोन डेविस

@AaronDavies - जो वास्तव में काम नहीं करता है। उन फ़ाइलनामों में से किसी में एक नई पंक्ति डालें और अपने लिए देखें। साथ ही, वही काम find . \! -name . -prune | wc -lजो आप करते हैं, उन्हें भी करना है: - जो अभी भी काम नहीं करता है, बेशक।
mikeserv

1
मैं अनुसरण नहीं करता - printfअनुदेश एक निरंतर स्ट्रिंग (एक नई पंक्ति) को प्रिंट करता है जिसमें फ़ाइल नाम बिल्कुल शामिल नहीं है, इसलिए परिणाम किसी भी अजीब फ़ाइलनाम से स्वतंत्र हैं। यह ट्रिक बिल्कुल भी नहीं की जा सकती है findजो समर्थन नहीं करती है printf, बेशक।
हारून डेविस

@AaronDavies - ओह, सच। मैंने मान लिया कि फिल्म का नाम शामिल था। यह, हालांकि, निश्चित रूप से किया जा सकता है:find .//. \!. -name . -prune | grep -c '^\.//\.'
mikeserv

प्रतिभाशाली! /केवल अन्य चरित्र होने के नाते जो फ़ाइल नाम में नहीं दिखाई दे सकते हैं, .//.अनुक्रम हर फ़ाइल के लिए एक बार दिखाई देने की गारंटी है, है ना? कुछ सवाल हालांकि - क्यों .//., और क्यों -prune? यह कब से अलग होगा find . \! -name . | grep -c '^\.'? (मुझे लगता है कि .आपके \!.में एक टाइपो है।)
हारून डेविस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.