जवाबों:
यह सरल वन-लाइनर किसी भी शेल में काम करना चाहिए, न कि केवल बैश:
ls -1q log* | wc -l
ls -1q आपको प्रति फ़ाइल एक पंक्ति देगा, भले ही उनके पास व्हॉट्सएप हो या विशेष वर्ण जैसे कि newlines।
आउटपुट को wc -l पर पाइप किया जाता है, जो लाइनों की संख्या को गिनता है।
lsकरता, क्योंकि यह एक बच्चे की प्रक्रिया बनाता है। log*शेल द्वारा विस्तारित किया जाता है, नहीं ls, इसलिए एक सरल काम echoकरेगा।
logsप्रश्न में निर्देशिका में एक निर्देशिका कहा जाता है, तो उस लॉग निर्देशिका की सामग्री को भी गिना जाएगा। यह शायद जानबूझकर नहीं है।
आप इसे सुरक्षित रूप से कर सकते हैं (यानी स्थान के साथ या \nउनके नाम की फाइलों द्वारा बग नहीं किया जाएगा )
$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
आपको सक्षम करने की आवश्यकता है nullglobताकि कोई फ़ाइल मेल न होने पर आपको सरणी*.log में शाब्दिक रूप से न मिले । ( "सेट -x" को "पूर्ववत करें" कैसे देखें ? उदाहरण के लिए इसे सुरक्षित रूप से कैसे रीसेट करें।)$logfiles
shopt -u nullglobको छोड़ दिया जाना चाहिए यदि nullglobआप परेशान नहीं थे तो आपने शुरू किया।
*.logबस के साथ प्रतिस्थापित *निर्देशिका की गणना करेगा। यदि आप जिन फ़ाइलों की गणना करना चाहते हैं, उनका पारंपरिक नामकरण कन्वेंशन है name.extension, तो उपयोग करें *.*।
यहाँ बहुत से उत्तर हैं, लेकिन कुछ को ध्यान में नहीं है
-l)*.logइसके बजाय थाlog*logsमैच कहा जाता है log*)यहाँ एक समाधान है जो उन सभी को संभालता है:
ls 2>/dev/null -Ubad1 -- log* | wc -l
स्पष्टीकरण:
-Ulsप्रविष्टियों को क्रमबद्ध नहीं करने का कारण बनता है, जिसका अर्थ है कि इसे पूरी निर्देशिका सूची को मेमोरी में लोड करने की आवश्यकता नहीं है-bप्रिंट्स सी-स्टाइल नॉनोग्राफिक कैरेक्टर्स के लिए बच जाती है, जो महत्वपूर्ण रूप से नई कहानियों को छापती है \n।-aसभी फाइलों को प्रिंट करता है, यहां तक कि छिपी हुई फाइलों (सख्ती की जरूरत नहीं है जब ग्लोब log*का अर्थ है छिपी हुई फाइलें नहीं)-dनिर्देशिका की सामग्री को सूचीबद्ध करने का प्रयास किए बिना निर्देशिकाओं को प्रिंट करता है, जो कि lsसामान्य रूप से होता है-1 यह सुनिश्चित करता है कि यह एक कॉलम पर है (ls पाइप से लिखते समय यह स्वचालित रूप से करता है, इसलिए यह कड़ाई से आवश्यक नहीं है)2>/dev/nullStderr को पुनर्निर्देशित करता है ताकि यदि 0 लॉग फ़ाइलें हों, तो त्रुटि संदेश को अनदेखा करें। (ध्यान दें कि इसके बजाय पूरी कामकाजी निर्देशिका को सूचीबद्ध shopt -s nullglobकरना होगा ls।)wc -lयह उत्पन्न होने के रूप में निर्देशिका लिस्टिंग की खपत करता है, इसलिए lsकिसी भी समय मेमोरी का आउटपुट कभी भी मेमोरी में नहीं होता है।--फ़ाइल नामों को कमांड से अलग किया --जाता है ताकि तर्क के रूप में नहीं समझा जा सके ls(मामले log*में हटा दिया गया है)शेल फ़ाइलों की पूरी सूची में विस्तारित हो जाएगाlog* , जो बहुत अधिक फ़ाइलों के होने पर मेमोरी को समाप्त कर सकता है, इसलिए फिर इसे grep के माध्यम से चलाना बेहतर होगा:
ls -Uba1 | grep ^log | wc -l
यह अंतिम मेमोरी की बहुत अधिक मात्रा का उपयोग किए बिना फ़ाइलों की बहुत बड़ी निर्देशिकाओं को संभालता है (यद्यपि यह एक उपधारा का उपयोग करता है)। यह -dअब आवश्यक नहीं है, क्योंकि यह केवल वर्तमान निर्देशिका की सामग्री को सूचीबद्ध कर रहा है।
पुनरावर्ती खोज के लिए:
find . -type f -name '*.log' -printf x | wc -c
wc -cके आउटपुट में वर्णों की संख्या की गणना करेगा find, जबकि प्रत्येक परिणाम के लिए एक प्रिंट करना -printf xबताता findहै x।
गैर-पुनरावर्ती खोज के लिए, यह करें:
find . -maxdepth 1 -type f -name '*.log' -printf x | wc -c
-name '*.log'तो यह सभी फाइलों की गणना करेगा, जो कि मुझे अपने उपयोग के मामले के लिए आवश्यक थी। इसके अलावा -maxdepth ध्वज अत्यंत उपयोगी है, धन्यवाद!
find; सिर्फ शब्दशः फ़ाइल नाम के अलावा कुछ और प्रिंट करें।
इस प्रश्न के लिए स्वीकृत उत्तर गलत है, लेकिन मेरे पास कम प्रतिनिधि हैं इसलिए इसमें कोई टिप्पणी नहीं दी जा सकती।
इस प्रश्न का सही उत्तर मैट द्वारा दिया गया है:
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
यदि आपके पास बहुत सारी फाइलें हैं और आप सुरुचिपूर्ण shopt -s nullglobऔर बाश सरणी समाधान का उपयोग नहीं करना चाहते हैं, तो आप फ़ाइल के नाम को प्रिंट नहीं कर सकते हैं, जब तक कि आप फ़ाइल नाम को प्रिंट नहीं कर सकते हैं।
find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l
यह लॉग से मेल खाने वाली सभी फ़ाइलों .*को ढूंढेगा * और जो कि "नहीं नाम। *" के साथ शुरू नहीं होता है, लेकिन यह महत्वपूर्ण है, लेकिन यह ध्यान रखना महत्वपूर्ण है कि "ls" के लिए डिफ़ॉल्ट डॉट-फाइल नहीं दिखाना है, लेकिन डिफ़ॉल्ट खोजने के लिए उन्हें शामिल करने के लिए है।
यह एक सही उत्तर है, और किसी भी प्रकार के फ़ाइल नाम को संभालता है जिसे आप इस पर फेंक सकते हैं, क्योंकि फ़ाइल का नाम कभी भी कमांडों के बीच नहीं होता है।
लेकिन, shopt nullglobजवाब सबसे अच्छा जवाब है!
findका उपयोग कर बनाम lsसमस्या के हल के लिए दो अलग-अलग तरीके हैं। findहमेशा एक मशीन पर मौजूद नहीं होता है, लेकिन lsआमतौर पर होता है,
findशायद उन सभी फैंसी विकल्पों के लिए lsभी नहीं है।
-maxdepth 1
findयह डिफ़ॉल्ट रूप से करता है। यह भ्रम पैदा कर सकता है यदि कोई महसूस नहीं करता है कि एक छिपा हुआ बच्चा फ़ोल्डर है, और यह lsकुछ परिस्थितियों में उपयोग करने के लिए लाभप्रद हो सकता है, जो डिफ़ॉल्ट रूप से छिपी हुई फ़ाइलों की रिपोर्ट नहीं करता है।
यहाँ इसके लिए मेरा एक लाइनर है।
file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)
set -- हमारे लिए तैयार होने के अलावा कुछ भी नहीं कर रहा है $#, कि शेल प्रोग्राम में पारित किए गए कमांड-लाइन तर्कों की संख्या
(टिप्पणी के लिए पर्याप्त प्रतिष्ठा नहीं)
यह बगिया है :
ls -1q some_pattern | wc -l
यदि shopt -s nullglobसेट किया जाता है, तो यह सभी नियमित फ़ाइलों की संख्या को प्रिंट करता है , न कि केवल पैटर्न वाले (CentOS-8 और Cygwin पर परीक्षण किए गए)। कौन जानता है कि अन्य अर्थहीन कीड़े क्या lsहैं?
यह सही है और बहुत तेज है:
shopt -s nullglob; files=(some_pattern); echo ${#files[@]};
यह अपेक्षित काम करता है।
0.006ऑन सेंटोस, और 0.083सिगविन (मामले में इसका उपयोग देखभाल के साथ किया जाता है)।
0.000सेंटोस पर, और 0.003सिगविन पर।
आप शेल फ़ंक्शन का उपयोग करके इस तरह के कमांड को आसानी से परिभाषित कर सकते हैं। इस पद्धति के लिए किसी बाहरी कार्यक्रम की आवश्यकता नहीं होती है और यह किसी भी बच्चे की प्रक्रिया को जन्म नहीं देती है। यह खतरनाक lsपार्सिंग का प्रयास नहीं करता है और "विशेष" अक्षर (व्हाट्सएप, न्यूलाइन, बैकस्लैश और इतने पर) को ठीक से संभालता है। यह केवल शेल द्वारा प्रदत्त फ़ाइल नाम विस्तार तंत्र पर निर्भर करता है। यह कम से कम sh, bash और zsh के साथ संगत है।
नीचे दी गई पंक्ति एक फ़ंक्शन को परिभाषित करती है, countजो उन तर्कों की संख्या को प्रिंट करती है जिनके साथ इसे बुलाया गया है।
count() { echo $#; }
बस इसे वांछित पैटर्न के साथ कॉल करें:
count log*
परिणाम के सही होने के लिए जब ग्लोबिंग पैटर्न का कोई मेल नहीं है, तो शेल विकल्प nullglob(या failglob- जो कि zsh पर डिफ़ॉल्ट व्यवहार है) को समय विस्तार होने पर सेट किया जाना चाहिए। इसे इस तरह सेट किया जा सकता है:
shopt -s nullglob # for sh / bash
setopt nullglob # for zsh
आप जो गिनना चाहते हैं, उसके आधार पर आपको शेल विकल्प में भी रुचि हो सकती है dotglob।
दुर्भाग्य से, कम से कम बैश के साथ, इन विकल्पों को स्थानीय रूप से सेट करना आसान नहीं है। यदि आप उन्हें विश्व स्तर पर सेट नहीं करना चाहते हैं, तो सबसे सीधा समाधान इस और अधिक जटिल तरीके से फ़ंक्शन का उपयोग करना है:
( shopt -s nullglob ; shopt -u failglob ; count log* )
यदि आप लाइटवेट सिंटैक्स को पुनर्प्राप्त करना चाहते हैं count log*, या यदि आप वास्तव में एक सब-स्पेलिंग से बचना चाहते हैं, तो आप कुछ लाइनों के साथ हैक कर सकते हैं:
# sh / bash:
# the alias is expanded before the globbing pattern, so we
# can set required options before the globbing gets expanded,
# and restore them afterwards.
count() {
eval "$_count_saved_shopts"
unset _count_saved_shopts
echo $#
}
alias count='
_count_saved_shopts="$(shopt -p nullglob failglob)"
shopt -s nullglob
shopt -u failglob
count'
एक बोनस के रूप में, यह फ़ंक्शन अधिक सामान्य उपयोग का है। उदाहरण के लिए:
count a* b* # count files which match either a* or b*
count $(jobs -ps) # count stopped jobs (sh / bash)
PATH से कॉल करने वाले फ़ंक्शन को स्क्रिप्ट फ़ाइल (या समतुल्य सी प्रोग्राम) में बदलकर, इसे ऐसे findऔर प्रोग्राम के साथ भी बनाया जा सकता है xargs:
find "$FIND_OPTIONS" -exec count {} \+ # count results of a search
मैंने इस उत्तर को बहुत सोचा है, विशेष रूप से नॉट-पार्से-एलएस सामान दिया है । पहले तो मैंने कोशिश की
<चेतावनी! काम नहीं किया>
du --inodes --files0-from=<(find . -maxdepth 1 -type f -print0) | awk '{sum+=int($1)}END{print sum}'
</ चेतावनी! काम नहीं किया>
अगर वहाँ केवल एक फ़ाइल नाम की तरह काम किया था
touch $'w\nlf.aa'
लेकिन असफल रहा अगर मैंने इस तरह का नाम बनाया
touch $'firstline\n3 and some other\n1\n2\texciting\n86stuff.jpg'
मैं अंत में नीचे क्या डाल रहा हूँ के साथ आया था। नोट मैं निर्देशिका में सभी फ़ाइलों की गिनती प्राप्त करने की कोशिश कर रहा था (किसी भी उपनिर्देशिका को शामिल नहीं)। मुझे लगता है कि, यह @Mat और @Dan_Yard द्वारा उत्तर के साथ-साथ, @mogsie द्वारा निर्धारित की गई कम से कम अधिकांश आवश्यकताएँ हैं (मुझे याद नहीं है।) मुझे लगता है कि @mogsie द्वारा उत्तर सही है। लेकिन मैं हमेशा पार्सिंग से दूर रहने की कोशिश करता हूं lsजब तक कि यह एक अत्यंत विशिष्ट स्थिति न हो।
awk -F"\0" '{print NF-1}' < <(find . -maxdepth 1 -type f -print0) | awk '{sum+=$1}END{print sum}'
अधिक आसानी से:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -print0) | \
awk '{sum+=$1}END{print sum}'
यह विशेष रूप से फ़ाइलों के लिए एक खोज कर रहा है, एक अशक्त चरित्र के साथ आउटपुट का परिसीमन (रिक्त स्थान और लाइनफ़ीड के साथ समस्याओं से बचने के लिए), फिर शून्य वर्णों की संख्या की गिनती कर रहा है। फ़ाइलों की संख्या शून्य वर्णों की संख्या से एक कम होगी, क्योंकि अंत में एक अशक्त चरित्र होगा।
ओपी के सवाल का जवाब देने के लिए, विचार करने के लिए दो मामले हैं
1) गैर-पुनरावर्ती खोज:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
2) पुनरावर्ती खोज। ध्यान दें कि -nameपैरामीटर के अंदर क्या है थोड़ा अलग व्यवहार (छिपी हुई फाइलें, आदि) के लिए बदलना पड़ सकता है।
awk -F"\0" '{print NF-1}' < \
<(find . -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
यदि कोई इस पर टिप्पणी करना चाहता है कि ये उत्तर उन लोगों की तुलना में कैसे हैं जिनका मैंने इस उत्तर में उल्लेख किया है, तो कृपया करें।
ध्यान दें, मुझे यह उत्तर प्राप्त करते समय इस विचार प्रक्रिया में मिला ।
यहाँ मैं हमेशा क्या करता हूँ:
ls लॉग * | awk 'END {प्रिंट NR}'
awk 'END{print NR}'के बराबर होना चाहिए wc -l।
ls -1 log* | wc -l
जिसका अर्थ है प्रति पंक्ति एक फ़ाइल की सूची और फिर लाइनों को गिनने के लिए पैरामीटर स्विचिंग के साथ शब्द गणना कमांड पर पाइप करें।
-l, क्योंकिstat(2)प्रत्येक फ़ाइल के लिए और गिनती के प्रयोजनों के लिए कुछ भी नहीं जोड़ता है।