मैं किसी विशेष एक्सटेंशन, और वे निर्देशिकाओं के साथ फाइलें कैसे गिन सकता हूं?


14

मैं जानना चाहता हूं कि .cएक बड़ी जटिल निर्देशिका संरचना में कितनी नियमित फाइलों का विस्तार है, और ये भी कि ये फाइलें कितनी निर्देशिकाओं में फैली हुई हैं। मुझे जो आउटपुट चाहिए वो सिर्फ दो नंबर का है।

मैंने यह प्रश्न देखा है कि फ़ाइलों की संख्या कैसे प्राप्त की जाए, लेकिन मुझे यह जानने की आवश्यकता है कि फाइलें कितनी निर्देशिकाओं में हैं।

  • मेरे फ़ाइलनाम (निर्देशिका सहित) में कोई भी वर्ण हो सकता है; वे इसके साथ शुरू कर सकते हैं .या -रिक्त स्थान या newlines हो सकते हैं।
  • मेरे पास कुछ सिम्लिंक हो सकते हैं जिनके नाम के साथ अंत होता है .c, और निर्देशिकाओं के लिए सहानुभूति होती है। मैं सिमिलिंक का पालन या गणना नहीं करना चाहता, या मैं कम से कम यह जानना चाहता हूं कि क्या और कब उन्हें गिना जा रहा है।
  • निर्देशिका संरचना में कई स्तर हैं और शीर्ष स्तर की निर्देशिका (कार्यशील निर्देशिका) में कम से कम एक .cफ़ाइल है।

मैंने जल्दबाजी में (बैश) शेल में कुछ कमांड लिखीं कि वे खुद को गिन सकें, लेकिन मुझे नहीं लगता कि परिणाम सटीक है ...

shopt -s dotglob
shopt -s globstar
mkdir out
for d in **/; do
     find "$d" -maxdepth 1 -type f -name "*.c" >> out/$(basename "$d")
done
ls -1Aq out | wc -l
cat out/* | wc -l

यह अस्पष्ट रीडायरेक्ट के बारे में शिकायतों का उत्पादन करता है, वर्तमान निर्देशिका में फ़ाइलों को याद करता है, और विशेष वर्णों पर यात्रा करता है (उदाहरण के लिए, पुनर्निर्देशित findआउटपुट फ़ाइलनामों में नईलाइन्स प्रिंट करता है ) और खाली फ़ाइलों (उफ़) का एक पूरा गुच्छा लिखता है।

मैं अपनी .cफ़ाइलों और उनकी निर्देशिकाओं को कैसे भरोसेमंद रूप से शामिल कर सकता हूं ?


यदि यह मदद करता है, तो बुरे नामों और सहूलियों के साथ एक परीक्षण संरचना बनाने के लिए यहां कुछ आदेश दिए गए हैं:

mkdir -p cfiles/{1..3}/{a..b} && cd cfiles
mkdir space\ d
touch -- i.c -.c bad\ .c 'terrible
.c' not-c .hidden.c
for d in space\ d 1 2 2/{a..b} 3/b; do cp -t "$d" -- *.c; done
ln -s 2 dirlink
ln -s 3/b/i.c filelink.c

परिणामी संरचना में, 7 निर्देशिकाओं में .cफाइलें होती हैं, और 29 नियमित फाइलें समाप्त होती हैं .c(यदि dotglobकमांड चलने पर बंद हो जाती है) (यदि मैंने गलत तरीके से देखा है, तो कृपया मुझे बताएं)। ये वो नंबर हैं जो मुझे चाहिए।

कृपया बेझिझक इस विशेष परीक्षण का उपयोग करें।

NB: किसी भी खोल या अन्य भाषा में उत्तर मेरे द्वारा जांचे और सराहे जाएंगे। अगर मुझे नए पैकेजों को स्थापित करना है, तो कोई समस्या नहीं है। यदि आप GUI समाधान जानते हैं, तो मैं आपको साझा करने के लिए प्रोत्साहित करता हूं (लेकिन मैं इसे परीक्षण करने के लिए पूरे DE को स्थापित करने के लिए इतनी दूर नहीं जा सकता) :) मैं Ubuntu MATE 17.10 का उपयोग करता हूं।


खराब प्रोग्रामिंग की आदतों से निपटने के लिए एक कार्यक्रम लिखना काफी चुनौतीपूर्ण रहा;)
WinEunuuchs2Unix

जवाबों:


16

मैंने आउटपुट की सहानुभूति के साथ जांच नहीं की है:

find . -type f -iname '*.c' -printf '%h\0' |
  sort -z |
  uniq -zc |
  sed -zr 's/([0-9]) .*/\1 1/' |
  tr '\0' '\n' |
  awk '{f += $1; d += $2} END {print f, d}'
  • findआदेश प्रत्येक की निर्देशिका का नाम प्रिंट .cयह पाता है फ़ाइल।
  • sort | uniq -cहमें प्रत्येक निर्देशिका में कितनी फाइलें देता है ( sortयहाँ अनावश्यक हो सकता है, निश्चित नहीं है)
  • इसके साथ sed, मैं निर्देशिका नाम को प्रतिस्थापित करता हूं 1, इस प्रकार सभी संभावित अजीब पात्रों को समाप्त कर देता हूं , बस गिनती और 1शेष के साथ
  • सक्षम करने के लिए मुझे newline- अलग आउटपुट के साथ परिवर्तित करने के लिए tr
  • जिसके बाद मैंने awk के साथ योग किया, कुल फ़ाइलों की संख्या और उन फ़ाइलों को शामिल करने वाली निर्देशिकाओं की संख्या प्राप्त करने के लिए। ध्यान दें कि dयहाँ अनिवार्य रूप से समान है NR। मैं कमांड 1में सम्मिलित करना छोड़ सकता sedथा, और बस NRयहाँ मुद्रित किया गया था, लेकिन मुझे लगता है कि यह थोड़ा स्पष्ट है।

जब तक tr, डेटा एनयूएल-सीमांकित है, सभी वैध फ़ाइलनामों के खिलाफ सुरक्षित है।


ज़ीश और बैश के साथ, आप printf %qएक उद्धृत स्ट्रिंग प्राप्त करने के लिए उपयोग कर सकते हैं , जिसमें इसमें नई लाइनें नहीं होंगी। तो, आप कुछ ऐसा करने में सक्षम हो सकते हैं:

shopt -s globstar dotglob nocaseglob
printf "%q\n" **/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'

हालाँकि, भले ही ** निर्देशिकाओं के लिए सीमलिंक का विस्तार करने के लिए नहीं माना जाता है , मैं bash 4.4.18 (1) (Ubuntu 16.04) पर वांछित आउटपुट नहीं प्राप्त कर सका।

$ shopt -s globstar dotglob nocaseglob
$ printf "%q\n" ./**/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
34 15
$ echo $BASH_VERSION
4.4.18(1)-release

लेकिन zsh ने ठीक काम किया, और कमांड को सरल बनाया जा सकता है:

$ printf "%q\n" ./**/*.c(D.:h) | awk '!c[$0]++ {d++} END {print NR, d}'
29 7

Dइस ग्लोब को डॉट फाइल्स को सेलेक्ट करने में सक्षम .करता है , रेगुलर फाइल्स को सलेक्ट करता है (इसलिए, सिम्लिंक नहीं), और :hकेवल डाइरेक्टरी पाथ को प्रिंट करता है न कि फाइलनाम (जैसे find' %h) ( फाइलनाम जेनरेशन और मॉडिफायर पर सेक्शन देखें )। इसलिए awk कमांड के साथ हमें केवल दिखने वाली अद्वितीय निर्देशिकाओं की संख्या की गणना करने की आवश्यकता है, और लाइनों की संख्या फ़ाइल गणना है।


वह तो कमाल है। का उपयोग करता है कि क्या जरूरत है और अधिक नहीं है। शिक्षण के लिए धन्यवाद :)
Zanna

@Zanna यदि आप कुछ कमांड्स को डायरेक्शंस स्ट्रक्चर को सिम्बलिंक के साथ रीक्रिएट करने के लिए और सिम्बलिंक के साथ अपेक्षित आउटपुट के लिए पोस्ट करते हैं, तो मैं इसे तदनुसार ठीक करने में सक्षम हो सकता हूं।
मूरू

मैंने कुछ आदेश जोड़ दिए हैं ताकि सहानुभूति के साथ एक (सामान्य रूप से जटिल) परीक्षण संरचना बनाई जा सके।
ज़न्ना

@ मुझे लगता है कि इस आदेश को प्राप्त करने के लिए किसी भी समायोजन की आवश्यकता नहीं है 29 7। अगर मैं जोड़ने -Lके लिए find, कि अप करने के लिए चला जाता है 41 10। आपको किस आउटपुट की आवश्यकता है?
मूरू

1
एक zsh + awk विधि जोड़ी। वहाँ शायद मेरे लिए गिनती मुद्रित करने के लिए खुद को zsh पाने के लिए कोई रास्ता है, लेकिन पता नहीं कैसे।
मुरु

11

पायथन के पास ऐसा काम है os.walk, जो इस तरह के आसान, सहज ज्ञान युक्त काम करता है, और अजीब तरह के फ़ाइलनामों के सामने भी स्वचालित रूप से मजबूत होता है, जैसे कि नईलाइन वर्ण। यह पायथन 3 स्क्रिप्ट, जिसे मैंने मूल रूप से चैट में पोस्ट किया था , को वर्तमान निर्देशिका में चलाने का इरादा है (लेकिन इसका वर्तमान निर्देशिका में स्थित होना आवश्यक नहीं है, और आप बदल सकते हैं कि यह किस मार्ग से गुजरती हैos.walk ):

#!/usr/bin/env python3

import os

dc = fc = 0
for _, _, fs in os.walk('.'):
    c = sum(f.endswith('.c') for f in fs)
    if c:
        dc += 1
        fc += c
print(dc, fc)

यह उन निर्देशिकाओं की गिनती को प्रिंट करता है जिनमें सीधे कम से कम एक फ़ाइल होती है जिसका नाम समाप्त होता है .c, उसके बाद एक स्थान होता है , उसके बाद फाइलों की गिनती होती है जिनके नाम में अंत होता है .c। "छिपी" फाइलें - .अर्थात् , फाइलें जिनके नाम के साथ शुरू होता है - शामिल हैं, और छिपी हुई निर्देशिकाएं समान रूप से ट्रैवर्स की गई हैं।

os.walk पुनरावर्ती एक निर्देशिका पदानुक्रम का पता लगाता है।यह सब निर्देशिकाओं रिकर्सिवली प्रारंभिक बिंदु आप इसे देने के लिए, तीन मानों में से एक टपल के रूप में उनमें से प्रत्येक के बारे में जानकारी उपज से सुलभ हैं विश्लेषण करता है, root, dirs, files। प्रत्येक निर्देशिका के लिए इसका पता लगाया जाता है (पहले वाले जिसका नाम आप इसे देते हैं सहित):

  • rootउस निर्देशिका का पथनाम रखता है। ध्यान दें कि यह सिस्टम के "रूट डाइरेक्टरी" /(और असंबंधित /root) से पूरी तरह से असंबंधित है, हालांकि अगर आप वहां से शुरू करते हैं तो यह उन लोगों के पास जाएगा । इस मामले में,root पथ .--ie, वर्तमान निर्देशिका पर शुरू होता है - और इसके नीचे हर जगह जाता है।
  • dirsसभी उपनिर्देशिकाओं के पथनामों की सूची रखता हैउस निर्देशिका के जिनका नाम वर्तमान में है root
  • filesउन सभी फ़ाइलों के पथनामों की सूची रखता है जो उस निर्देशिका में रहती हैं जिसका नाम वर्तमान में है, rootलेकिन वे स्वयं निर्देशिका नहीं हैं। ध्यान दें कि इसमें नियमित फ़ाइलों की तुलना में अन्य प्रकार की फाइलें शामिल हैं, जिनमें प्रतीकात्मक लिंक शामिल हैं, लेकिन ऐसा लगता है कि आप ऐसी किसी भी प्रविष्टि के समाप्त होने की उम्मीद नहीं करते हैं.c से देखने में रुचि रखते हैं।

इस मामले में, मुझे केवल टपल के तीसरे तत्व की जांच करने की आवश्यकता है, files(जिसे मैं fsस्क्रिप्ट में कहता हूं )। findकमान की तरह , पायथन ने os.walkमेरे लिए उपनिर्देशिकाओं में भाग लिया; केवल एक चीज जो मुझे स्वयं का निरीक्षण करना है, उनमें से प्रत्येक में फ़ाइलों का नाम है। से भिन्नfindकमांड के , हालांकि, os.walkस्वचालित रूप से मुझे उन फ़ाइलनामों की एक सूची प्रदान करता है।

वह स्क्रिप्ट प्रतीकात्मक लिंक का पालन नहीं करता है। आप शायद बहुत इस तरह के ऑपरेशन के लिए सिम्बलिंक का पालन नहीं करना चाहते हैं, क्योंकि वे चक्र बना सकते हैं, और क्योंकि अगर कोई चक्र नहीं हैं, तो समान फ़ाइलों और निर्देशिकाओं को अलग-अलग कई बार गिना जा सकता है, यदि वे अलग-अलग सिमलिंक के माध्यम से सुलभ हैं।

यदि आप कभी भी os.walkसहानुभूति का पालन करना चाहते हैं - जो आप आमतौर पर नहीं करेंगे - तो आप इसे पास कर सकते हैं followlinks=true। यानी लिखने के बजाय os.walk('.')आप लिख सकते थे os.walk('.', followlinks=true)। मैं दोहराता हूं कि आप शायद ही कभी ऐसा चाहते हैं, विशेष रूप से इस तरह के कार्य के लिए जहां आप एक पूरी निर्देशिका संरचना की पुनरावृत्ति कर रहे हैं, चाहे वह कितना भी बड़ा हो, और इसमें सभी फाइलों की गिनती हो जो कुछ आवश्यकता को पूरा करती हैं।


7

ढूँढें + पर्ल:

$ find . -type f -iname '*.c' -printf '%h\0' | 
    perl -0 -ne '$k{$_}++; }{ print scalar keys %k, " $.\n" '
7 29

व्याख्या

find(ताकि कोई सिमलिंक या निर्देशिका) आदेश किसी भी नियमित फ़ाइलों मिलेगा और फिर निर्देशिका का नाम वे में हैं प्रिंट ( %h) के द्वारा पीछा किया \0

  • perl -0 -ne: लाइन द्वारा इनपुट लाइन पढ़ें ( -n) और -eप्रत्येक लाइन द्वारा दी गई स्क्रिप्ट को लागू करें । -0के लिए इनपुट लाइन विभाजक सेट \0तो हम अशक्त-सीमांकित इनपुट पढ़ सकते हैं।
  • $k{$_}++: $_एक विशेष चर है जो वर्तमान रेखा का मान लेता है। इसका उपयोग हैश की कुंजी के रूप में किया जाता है %k , जिसका मान प्रत्येक इनपुट लाइन (डायरेक्टरी नाम) की संख्या को देखा जाता है।
  • }{: यह लेखन का एक संक्षिप्त तरीका है END{}। के बाद कोई भी आदेश}{ को संसाधित किए एक बार निष्पादित जाएगा।
  • print scalar keys %k, " $.\n": keys %kहैश में कुंजियों की एक सरणी देता है %kscalar keys %kउस सरणी में तत्वों की संख्या देता है, देखी गई निर्देशिकाओं की संख्या। यह वर्तमान मूल्य के साथ मुद्रित होता है $., एक विशेष चर जो वर्तमान इनपुट लाइन संख्या रखता है। चूंकि यह अंत में चलाया जाता है, वर्तमान इनपुट लाइन संख्या अंतिम पंक्ति की संख्या होगी, इसलिए अब तक देखी गई लाइनों की संख्या।

आप स्पष्टता के लिए इस के लिए पर्ल कमांड का विस्तार कर सकते हैं:

find  . -type f -iname '*.c' -printf '%h\0' | 
    perl -0 -e 'while($line = <STDIN>){
                    $dirs{$line}++; 
                    $tot++;
                } 
                $count = scalar keys %dirs; 
                print "$count $tot\n" '

4

यहाँ मेरा सुझाव है:

#!/bin/bash
tempfile=$(mktemp)
find -type f -name "*.c" -prune >$tempfile
grep -c / $tempfile
sed 's_[^/]*$__' $tempfile | sort -u | grep -c /

यह लघु लिपि एक गतिरोध पैदा करती है, हर फ़ाइल को समाप्त होने वाली वर्तमान निर्देशिका के अंतर्गत खोजती है .cऔर टेंपफ़िले में सूची लिखती है। grepतब फ़ाइलों को गिनने के लिए उपयोग किया जाता है (निम्नलिखित में मैं कमांड लाइन का उपयोग करके किसी निर्देशिका में फ़ाइलों की एक गिनती कैसे प्राप्त कर सकता हूं? ) दो बार: दूसरी बार, कई बार सूचीबद्ध की गई निर्देशिकाओं का उपयोग करके sort -uप्रत्येक पंक्ति से फ़ाइल नाम हटाने के बाद उपयोग किया जाता है sed

यह फ़ाइल नाम में नई सूचियों के साथ भी ठीक से काम करता है: grep -c /केवल एक स्लैश वाली रेखाओं को गिनता है और इसलिए सूची में एक बहु-पंक्ति फ़ाइल नाम की केवल पहली पंक्ति को मानता है।

उत्पादन

$ tree
.
├── 1
   ├── 1
      ├── test2.c
      └── test.c
   └── 2
       └── test.c
└── 2
    ├── 1
       └── test.c
    └── 2

$ tempfile=$(mktemp);find -type f -name "*.c" -prune >$tempfile;grep -c / $tempfile;sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
4
3

4

छोटे गोले

मैं दो मुख्य कमांड लाइनों (और एक चर filetypeको आसान बनाने के लिए स्विच करने के लिए अन्य फ़ाइल देखने के लिए स्विच करने के लिए) के साथ एक छोटी सी बैश शेल्ट्री का सुझाव देता हूं ।

यह केवल नियमित फ़ाइलों के लिए या सहानुभूति में नहीं दिखता है।

#!/bin/bash

filetype=c
#filetype=pdf

# count the 'filetype' files

find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l | tr '\n' ' '

# count directories containing 'filetype' files

find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l

वर्बोस शेलस्क्रिप्ट

यह एक अधिक वर्बोज़ संस्करण है जो प्रतीकात्मक लिंक पर भी विचार करता है,

#!/bin/bash

filetype=c
#filetype=pdf

# counting the 'filetype' files

echo -n "number of $filetype files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l

echo -n "number of $filetype symbolic links in the current directory tree: "
find -type l -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype normal files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree including linked directories: "
find -L -type f -name "*.$filetype" -ls 2> /tmp/c-counter |sed 's#.* \./##' | wc -l; cat /tmp/c-counter; rm /tmp/c-counter

# list directories with and without 'filetype' files (good for manual checking; comment away after test)
echo '---------- list directories:'
 find    -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
#find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;

# count directories containing 'filetype' files

echo -n "number of directories with $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l

# list and count directories including symbolic links, containing 'filetype' files
echo '---------- list all directories including symbolic links:'
find -L -type d -exec bash -c "ls -AF '{}' |grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
echo -n "number of directories (including symbolic links) with $filetype files: "
find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \; 2>/dev/null |grep 'contains file(s)$'|wc -l

# count directories without 'filetype' files (good for checking; comment away after test)

echo -n "number of directories without $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null || echo '{} empty'" \;|grep 'empty$'|wc -l

परीक्षण उत्पादन

लघु शेलस्क्रिप्ट से:

$ ./ccntr 
29 7

क्रिया गोले से:

$ LANG=C ./c-counter
number of c files in the current directory tree: 29
number of c symbolic links in the current directory tree: 1
number of c normal files in the current directory tree: 29
number of c symbolic links in the current directory tree including linked directories: 42
find: './cfiles/2/2': Too many levels of symbolic links
find: './cfiles/dirlink/2': Too many levels of symbolic links
---------- list directories:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)

number of directories with c files: 7
---------- list all directories including symbolic links:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
find: './cfiles/2/2': Too many levels of symbolic links
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/dirlink empty
find: './cfiles/dirlink/2': Too many levels of symbolic links
./cfiles/dirlink/b contains file(s)
./cfiles/dirlink/a contains file(s)
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)

number of directories (including symbolic links) with c files: 9
number of directories without c files: 5
$ 

4

सरल पर्ल एक लाइनर:

perl -MFile::Find=find -le'find(sub{/\.c\z/ and -f and $c{$File::Find::dir}=++$c}, @ARGV); print 0 + keys %c, " $c"' dir1 dir2

या findआदेश के साथ सरल :

find dir1 dir2 -type f -name '*.c' -printf '%h\0' | perl -l -0ne'$c{$_}=1}{print 0 + keys %c, " $."'

यदि आपको गोल्फ पसंद है और हाल ही में (जैसे दशक से भी कम पुराने) पर्ल:

perl -MFile::Find=find -E'find(sub{/\.c$/&&-f&&($c{$File::Find::dir}=++$c)},".");say 0+keys%c," $c"'
find -type f -name '*.c' -printf '%h\0'|perl -0nE'$c{$_}=1}{say 0+keys%c," $."'

2

उस locateकमांड का उपयोग करने पर विचार करें जो findकमांड की तुलना में बहुत तेज है ।

परीक्षण डेटा पर चल रहा है

$ sudo updatedb # necessary if files in focus were added `cron` daily.
$ printf "Number Files: " && locate -0r "$PWD.*\.c$" | xargs -0 -I{} sh -c 'test ! -L "$1" && echo "regular file"' _  {} | wc -l &&  printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -cu | wc -l
Number Files: 29
Number Dirs.: 7

यूनिक्स और लिनक्स उत्तर में फ़ाइल गिनती से बाहर प्रतीकात्मक लिंक के माध्यम से मेरी मदद करने के लिए उसके उत्तर के लिए मूरू का धन्यवाद ।

यूनिक्स और लिनक्स उत्तर$PWD में (मेरे द्वारा निर्देशित नहीं) के अपने जवाब के लिए टेर्डन का धन्यवाद


नीचे मूल उत्तर टिप्पणियों द्वारा संदर्भित है

संक्षिप्त रूप:

$ cd /
$ sudo updatedb
$ printf "Number Files: " && locate -cr "$PWD.*\.c$"
Number Files: 3523
$ printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l 
Number Dirs.: 648
  • sudo updatedblocateयदि .cआज फाइलें बनाई गई हैं या आपने डिलीट की हैं, तो कमांड द्वारा इस्तेमाल किया गया अपडेट डेटाबेस.c फाइलें ।
  • locate -cr "$PWD.*\.c$".cवर्तमान निर्देशिका में सभी फ़ाइलों का पता लगाएं और यह बच्चों ( $PWD) है। फ़ाइल नाम प्रिंट करने के बजाय, और -cतर्क के साथ प्रिंट गणना । rनिर्दिष्ट डिफ़ॉल्ट के बजाय regex*pattern* मिलान जो बहुत अधिक परिणाम प्राप्त हो सकते हैं।
  • locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l*.cवर्तमान निर्देशिका में और नीचे सभी फ़ाइलों का पता लगाएँ । sedकेवल निर्देशिका नाम छोड़ने के साथ फ़ाइल नाम निकालें । प्रत्येक निर्देशिका में फ़ाइलों की संख्या का उपयोग करके uniq -c। के साथ निर्देशिकाओं की संख्या की गणना करें wc -l

एक-लाइनर के साथ वर्तमान निर्देशिका में शुरू करें

$ cd /usr/src
$ printf "Number Files: " && locate -cr "$PWD.*\.c$" &&  printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Files: 3430
Number Dirs.: 624

ध्यान दें कि फ़ाइल गणना और निर्देशिका गणना कैसे बदल गई है। मेरा मानना ​​है कि सभी उपयोगकर्ताओं के पास /usr/srcनिर्देशिका है और स्थापित गुठली की संख्या के आधार पर अलग-अलग गणना के साथ कमांड चला सकते हैं।

लंबा फार्म:

लंबे फॉर्म में वह समय शामिल होता है जिससे आप देख सकते हैं कि कितना तेज locateहै find। यहां तक ​​कि अगर आपको sudo updatedbइसे चलाना है तो एकल की तुलना में कई गुना तेज है find /

───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ sudo time updatedb
0.58user 1.32system 0:03.94elapsed 48%CPU (0avgtext+0avgdata 7568maxresident)k
48inputs+131920outputs (1major+3562minor)pagefaults 0swaps
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Files: " && locate -cr $PWD".*\.c$")
Number Files: 3523

real    0m0.775s
user    0m0.766s
sys     0m0.012s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate -r $PWD".*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l) 
Number Dirs.: 648

real    0m0.778s
user    0m0.788s
sys     0m0.027s
───────────────────────────────────────────────────────────────────────────────────────────

नोट: यह सभी ड्राइव और विभाजनों की सभी फाइलें हैं । यानी हम विंडोज कमांड भी खोज सकते हैं:

$ time (printf "Number Files: " && locate *.exe -c)
Number Files: 6541

real    0m0.946s
user    0m0.761s
sys     0m0.060s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate *.exe | sed 's%/[^/]*$%/%' | uniq -c | wc -l) 
Number Dirs.: 3394

real    0m0.942s
user    0m0.803s
sys     0m0.092s

मेरे पास तीन विंडोज 10 एनटीएफएस विभाजन स्वचालित रूप से घुड़सवार हैं /etc/fstab । जागरूक बनो सब कुछ पता है!

दिलचस्प गणना:

$ time (printf "Number Files: " && locate / -c &&  printf "Number Dirs.: " && locate / | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Files: 1637135
Number Dirs.: 286705

real    0m15.460s
user    0m13.471s
sys     0m2.786s

286,705 निर्देशिका में 1,637,135 फाइलों को गिनने में 15 सेकंड का समय लगता है। YMMV।

locateकमांड रेगेक्स हैंडलिंग पर एक विस्तृत ब्रेकडाउन के लिए (इस प्रश्नोत्तर में उपयोग किए जाने की आवश्यकता नहीं है, लेकिन सिर्फ मामले में उपयोग किया जाता है) कृपया इसे पढ़ें: कुछ विशिष्ट निर्देशिका के तहत "पता लगाएं" का उपयोग करें?

हाल के लेखों से अतिरिक्त पढ़ना:


1
यह एक विशिष्ट निर्देशिका में फ़ाइलों की गणना नहीं करता है। जैसा कि आप बताते हैं, यह सभी फाइलों (या निर्देशिकाओं, या किसी अन्य प्रकार की फ़ाइल) से मेल खाता है .c(ध्यान दें कि यदि -.cआप उद्धृत नहीं कर रहे हैं, तो वर्तमान निर्देशिका में नाम वाली फ़ाइल है *.c) तो यह टूट जाएगी और फिर यह सभी निर्देशिकाओं को प्रिंट कर देगी। सिस्टम में, भले ही वे .c फाइलें हों।
टेर्डन

@terdon आप एक निर्देशिका पास कर सकते हैं ~/my_c_progs/*.c। यह .cकार्यक्रमों के साथ 638 निर्देशिकाओं की गिनती कर रहा है, कुल निर्देशिका बाद में शो के रूप में है 286,705। मैं दोहरे उद्धरण के उत्तर को संशोधित करूँगा '' * .सी "। पारितोषिक के लिए धन्यवाद।
विनयुनुच्स

3
हां, आप कुछ का उपयोग कर सकते हैं locate -r "/path/to/dir/.*\.c$", लेकिन इसका आपके उत्तर में कहीं भी उल्लेख नहीं किया गया है। आप केवल एक और उत्तर के लिए एक लिंक देते हैं, जिसमें इसका उल्लेख है लेकिन यहां दिए गए प्रश्न का उत्तर देने के लिए इसे कैसे अनुकूलित किया जाए, इसकी कोई व्याख्या नहीं है। आपका पूरा उत्तर सिस्टम पर कुल फ़ाइलों और निर्देशिकाओं की गणना करने के तरीके पर केंद्रित है, जो कि पूछे गए प्रश्न के लिए प्रासंगिक नहीं है "मैं कैसे .c फ़ाइलों की संख्या और निर्देशिकाओं की संख्या की गणना कर सकता हूं।" सी एक विशिष्ट निर्देशिका में फ़ाइलें "। इसके अलावा, आपके नंबर गलत हैं, इसे ओपी में उदाहरण पर आज़माएं।
टेराडॉन

@terdon आपके इनपुट के लिए धन्यवाद। मैंने आपके सुझावों के साथ उत्तर में सुधार किया है और एक उत्तर जिसे आपने अन्य एसई साइट पर $PWDचर के लिए पोस्ट किया है : unix.stackexchange.com/a/188191/200094
WinEunuuchs2Unix

1
अब आपको यह सुनिश्चित करना है कि $PWDऐसे वर्ण शामिल नहीं हैं जो शायद regex में विशेष है
muru
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.