ฉันจะนับไฟล์ที่มีนามสกุลเฉพาะและไดเรกทอรีที่อยู่ในนั้นได้อย่างไร


14

ฉันต้องการทราบจำนวนไฟล์ปกติที่มีส่วนขยาย.cในโครงสร้างไดเรกทอรีขนาดใหญ่ที่ซับซ้อนและจำนวนไดเรกทอรีไฟล์เหล่านี้จะกระจายไปทั่ว ผลลัพธ์ที่ฉันต้องการเป็นเพียงตัวเลขสองตัวนั้น

ฉันเคยเห็นคำถามนี้เกี่ยวกับวิธีรับจำนวนไฟล์ แต่ฉันจำเป็นต้องทราบจำนวนไดเรกทอรีที่ไฟล์อยู่ด้วย

  • ชื่อไฟล์ของฉัน (รวมถึงไดเรกทอรี) อาจมีอักขระใด ๆ พวกเขาอาจเริ่มต้นด้วย.หรือ-และมีช่องว่างหรือขึ้นบรรทัดใหม่
  • ฉันอาจมี symlink ที่ชื่อลงท้ายด้วย.cและ symlink ไปยังไดเรกทอรี ฉันไม่ต้องการให้มีการติดตามหรือนับจำนวน symlink หรืออย่างน้อยฉันก็ต้องการทราบว่าพวกเขาจะถูกนับเมื่อใดและเมื่อใด
  • โครงสร้างไดเรกทอรีมีหลายระดับและไดเรกทอรีระดับบนสุด (ไดเรกทอรีทำงาน) มี.cไฟล์อย่างน้อยหนึ่งไฟล์

ฉันรีบเขียนคำสั่งบางอย่างในเชลล์ (Bash) เพื่อนับมันด้วยตัวเอง แต่ฉันไม่คิดว่าผลลัพธ์จะแม่นยำ ...

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ไฟล์และไดเรกทอรีที่มีไฟล์เหล่านั้นได้อย่างน่าเชื่อถือได้อย่างไร


ในกรณีที่ช่วยได้นี่คือคำสั่งเพื่อสร้างโครงสร้างการทดสอบที่มีชื่อไม่ดีและ symlink

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

ฉันไม่ได้ตรวจสอบผลลัพธ์ด้วย symlinks แต่:

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เหลือ
  • ทำให้ฉันสามารถแปลงเป็นเอาต์พุตที่คั่นด้วยบรรทัดใหม่ด้วย tr
  • ซึ่งฉันรวมกับ awk เพื่อรับจำนวนไฟล์ทั้งหมดและจำนวนไดเรกทอรีที่มีไฟล์เหล่านั้น โปรดทราบว่านี่เป็นหลักเช่นเดียวกับd NRฉันสามารถละเว้นการแทรก1ในsedคำสั่งและพิมพ์NRที่นี่ แต่ฉันคิดว่านี่ชัดเจนกว่าเล็กน้อย

จนถึงtrข้อมูลจะถูกคั่นด้วย NUL ปลอดภัยต่อชื่อไฟล์ที่ถูกต้องทั้งหมด


ด้วย zsh และ bash คุณสามารถใช้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เปิดใช้งาน glob นี้เพื่อเลือกไฟล์ dot เลือกไฟล์.ปกติ (ดังนั้นไม่ใช่ symlink) และ:hพิมพ์เฉพาะพา ธ ไดเร็กทอรีและไม่ใช่ชื่อไฟล์ (เช่นfind's %h) (ดูส่วนต่างๆในการสร้างชื่อไฟล์และโมดิฟายเออร์ ) ดังนั้นด้วยคำสั่ง awk เราเพียงแค่ต้องนับจำนวนไดเรกทอรีที่ไม่ซ้ำกันและจำนวนบรรทัดคือจำนวนไฟล์


ที่น่ากลัว. ใช้สิ่งที่จำเป็นและไม่มาก ขอบคุณสำหรับการสอน :)
Zanna

@ Zanna หากคุณโพสต์คำสั่งบางอย่างเพื่อสร้างโครงสร้างไดเรกทอรีใหม่ด้วย symlinks และผลลัพธ์ที่คาดหวังด้วย symlinks ฉันอาจสามารถแก้ไขปัญหานี้ได้
muru

ฉันได้เพิ่มคำสั่งบางอย่างเพื่อสร้างโครงสร้างการทดสอบ (ไม่จำเป็นต้องซับซ้อนตามปกติ) ด้วย symlinks
Zanna

@Zanna ผมคิดว่าคำสั่งนี้ไม่จำเป็นต้องปรับเปลี่ยนใด ๆ 29 7ที่จะได้รับ ถ้าผมเพิ่ม-Lเพื่อที่จะไปถึงfind 41 10ผลลัพธ์ใดที่คุณต้องการ
muru

1
เพิ่มวิธีการ zsh + awk อาจมีวิธีที่จะทำให้ zsh เป็นตัวพิมพ์จำนวนสำหรับฉัน แต่ก็ไม่รู้ว่าจะทำอย่างไร
muru

11

Python มี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เริ่มต้นที่เส้นทาง.- คือไดเรกทอรีปัจจุบัน - และไปทุกที่ด้านล่าง
  • dirsมีรายการของ pathnames ทั้งหมดที่ไดเรกทอรีย่อยrootของไดเรกทอรีที่มีชื่ออยู่ในขณะนี้ใน
  • filesเก็บรายการชื่อพา ธ ของไฟล์ทั้งหมดที่อยู่ในไดเรกทอรีที่มีชื่ออยู่ในขณะนี้rootแต่ไม่ใช่ไดเรกทอรี โปรดทราบว่านี่รวมถึงไฟล์ประเภทอื่นที่ไม่ใช่ไฟล์ปกติรวมถึงลิงก์สัญลักษณ์ แต่ดูเหมือนว่าคุณไม่คาดหวังว่ารายการดังกล่าวจะสิ้นสุด.cและสนใจที่จะเห็นสิ่งที่ทำ

ในกรณีนี้ฉันเพียงแค่ต้องตรวจสอบองค์ประกอบที่สามของ tuple files(ซึ่งฉันเรียกfsในสคริปต์) เช่นเดียวกับfindคำสั่ง Python os.walkลัดเลาะเข้าไปในไดเรกทอรีย่อยสำหรับฉัน; สิ่งเดียวที่ฉันต้องตรวจสอบตัวเองคือชื่อของไฟล์แต่ละไฟล์มี ไม่เหมือนกับfindคำสั่ง แต่os.walkให้รายชื่อไฟล์เหล่านั้นโดยอัตโนมัติ

สคริปต์นั้นไม่ได้ติดตามลิงก์สัญลักษณ์ คุณอาจไม่ต้องการ symlink ที่ตามมาสำหรับการดำเนินการดังกล่าวเนื่องจากพวกเขาสามารถสร้างวงจรและแม้ว่าจะไม่มีรอบก็ตามไฟล์และไดเรกทอรีเดียวกันอาจถูกสำรวจและนับหลายครั้งหากสามารถเข้าถึงได้ผ่าน symlink ที่แตกต่างกัน

หากคุณต้องการos.walkติดตาม symlinks ซึ่งโดยปกติแล้วคุณจะไม่ทำคุณก็สามารถผ่านfollowlinks=trueไปได้ นั่นคือแทนที่จะเขียนos.walk('.')คุณสามารถเขียนos.walk('.', followlinks=true)ได้ ฉันขอย้ำว่าคุณแทบจะไม่ต้องการสิ่งนั้นโดยเฉพาะอย่างยิ่งสำหรับงานเช่นนี้ที่คุณระบุโครงสร้างไดเรกทอรีทั้งหมดซ้ำ ๆ ไม่ว่ามันจะใหญ่แค่ไหนและนับจำนวนไฟล์ทั้งหมดที่ตรงกับความต้องการ


7

ค้นหา + Perl:

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

คำอธิบาย

findคำสั่งจะพบไฟล์ปกติใด ๆ (จึงไม่มี symlinks หรือไดเรกทอรี) แล้วพิมพ์ชื่อของไดเรกทอรีที่พวกเขาอยู่ใน ( %h) \0ตามด้วย

  • perl -0 -ne: อ่านบรรทัดอินพุตตามบรรทัด ( -n) และใช้สคริปต์ที่กำหนดโดย-eกับแต่ละบรรทัด การ-0ตั้งค่าตัวแยกบรรทัดอินพุตเป็น\0ดังนั้นเราจึงสามารถอ่านอินพุตที่คั่นด้วย null ได้
  • $k{$_}++: $_เป็นตัวแปรพิเศษที่รับค่าของบรรทัดปัจจุบัน ใช้เป็นกุญแจในการแฮช %kซึ่งมีค่าเป็นจำนวนครั้งที่แต่ละบรรทัดอินพุต (ชื่อไดเร็กทอรี) ถูกมองเห็น
  • }{: END{}นี้เป็นวิธีของการเขียนชวเลข คำสั่งใด ๆ หลังจากนั้น}{จะถูกดำเนินการหนึ่งครั้งหลังจากที่ทุกอินพุตได้รับการประมวลผล
  • print scalar keys %k, " $.\n": ส่งกลับอาร์เรย์ของคีย์ในกัญชาkeys %k ให้จำนวนองค์ประกอบในอาร์เรย์นั้นจำนวนไดเรกทอรีที่เห็น สิ่งนี้ถูกพิมพ์พร้อมกับค่าปัจจุบันของตัวแปรพิเศษที่เก็บหมายเลขบรรทัดอินพุตปัจจุบัน เนื่องจากสิ่งนี้รันที่ท้ายหมายเลขบรรทัดอินพุตปัจจุบันจะเป็นหมายเลขของบรรทัดสุดท้ายดังนั้นจำนวนบรรทัดที่เห็นจนถึงปัจจุบัน%kscalar keys %k$.

คุณสามารถขยายคำสั่ง perl ไปที่นี้เพื่อความชัดเจน:

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 /

สคริปต์สั้นนี้สร้าง tempfile ค้นหาทุกไฟล์ในและภายใต้ไดเรกทอรีปัจจุบันที่ลงท้ายด้วย.cและเขียนรายการไปยัง tempfile grepที่ใช้แล้วเพื่อนับไฟล์ (ต่อไปนี้ฉันจะได้รับการนับจำนวนของไฟล์ในไดเรกทอรีใช้บรรทัดคำสั่ง? ) ครั้งที่สอง: ครั้งที่สองไดเรกทอรีที่มีการระบุไว้หลายครั้งจะถูกลบออกใช้หลังจากปอกชื่อไฟล์จากแต่ละสายโดยใช้sort -used

นอกจากนี้ยังทำงานอย่างถูกต้องกับการขึ้นบรรทัดใหม่ในชื่อไฟล์: 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

หอยขนาดเล็ก

ฉันแนะนำ bash shellscript ขนาดเล็กที่มีสองบรรทัดคำสั่งหลัก (และตัวแปรfiletypeเพื่อให้ง่ายต่อการสลับเพื่อค้นหาประเภทไฟล์อื่น ๆ )

มันไม่ได้มองหาหรือใน symlink เพียงไฟล์ปกติ

#!/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

verbose shellscript

นี่เป็นเวอร์ชั่น verbose ที่พิจารณาลิงค์สัญลักษณ์

#!/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

จาก verbose shellscript:

$ 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 ง่าย ๆ หนึ่งซับ:

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:

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

ขอขอบคุณที่ Muru สำหรับคำตอบของเขาจะช่วยให้ฉันผ่านการลอกการเชื่อมโยงสัญลักษณ์จากจำนวนแฟ้มในUnix และ Linux คำตอบ

ขอบคุณ Terdon สำหรับคำตอบของเขา$PWD(ไม่ใช่บอกที่ฉัน) ใน Unix และ Linux คำตอบ


คำตอบเดิมด้านล่างอ้างอิงโดยความคิดเห็น

แบบสั้น:

$ 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 updatedbอัปเดตฐานข้อมูลที่ใช้โดยlocateคำสั่งหาก.cไฟล์ถูกสร้างขึ้นในวันนี้หรือหากคุณลบไปแล้ว.cไฟล์วันนี้
  • locate -cr "$PWD.*\.c$"ค้นหา.cไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันและเป็นลูก ( $PWD) แทนที่จะพิมพ์ชื่อไฟล์และนับการพิมพ์ด้วย-cอาร์กิวเมนต์ การrระบุ regex แทนการเริ่มต้น*pattern*จับคู่ซึ่งสามารถให้ผลลัพธ์ที่มากเกินไป
  • locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l. ค้นหา*.cไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันและด้านล่าง ลบชื่อไฟล์โดยsedทิ้งชื่อไดเรกทอรีเท่านั้น นับจำนวนของไฟล์ในแต่ละ directory 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 updatedbfind /

───────────────────────────────────────────────────────────────────────────────────────────
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
───────────────────────────────────────────────────────────────────────────────────────────

หมายเหตุ:นี่คือไฟล์ทั้งหมดในไดรฟ์และพาร์ทิชันทั้งหมด เช่นเราสามารถค้นหาคำสั่งของ Windows ได้เช่นกัน:

$ 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

ฉันมีพาร์ติชัน Windows 10 NTFS สามตัวที่เมาท์โดยอัตโนมัติ /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

ใช้เวลา 15 วินาทีในการนับไฟล์ 1,637,135 ไฟล์ในไดเรกทอรี 286,705 YMMV

สำหรับรายละเอียดเกี่ยวกับlocateการจัดการ regex ของคำสั่ง (ไม่จำเป็นต้องใช้ในคำถาม & คำตอบนี้ แต่ใช้ในกรณี) โปรดอ่านสิ่งนี้: ใช้ "ค้นหา" ภายใต้ไดเรกทอรีบางอย่าง?

อ่านเพิ่มเติมจากบทความล่าสุด:


1
สิ่งนี้จะไม่นับไฟล์ในไดเรกทอรีเฉพาะ เมื่อคุณชี้ให้เห็นมันจะนับการจับคู่ไฟล์ทั้งหมด (หรือไดเรกทอรีหรือไฟล์ประเภทอื่น ๆ ) .c(โปรดทราบว่ามันจะแตกถ้ามีไฟล์ชื่อ-.cในไดเรกทอรีปัจจุบันเนื่องจากคุณไม่ได้อ้างอิง*.c) แล้วมันจะพิมพ์ไดเรกทอรีทั้งหมด ในระบบโดยไม่คำนึงว่ามีไฟล์. c อยู่หรือไม่
terdon

@terdon ~/my_c_progs/*.cคุณสามารถส่งผ่านไดเรกทอรี มันนับ 638 ไดเรกทอรีที่มีโปรแกรมไดเรกทอรีทั้งหมดคือการแสดงต่อมาเป็น.c 286,705ฉันจะแก้ไขคำตอบเพื่อพูดสองครั้ง `" * .c " ขอบคุณสำหรับทิป.
WinEunuuchs2Unix

3
ใช่คุณสามารถใช้สิ่งที่ชอบlocate -r "/path/to/dir/.*\.c$"แต่ไม่ได้กล่าวถึงในคำตอบของคุณ คุณให้ลิงก์ไปยังคำตอบอื่นที่กล่าวถึงนี้ แต่ไม่มีคำอธิบายถึงวิธีการปรับแก้เพื่อตอบคำถามที่ถูกถามที่นี่ คำตอบทั้งหมดของคุณมุ่งเน้นไปที่วิธีการนับจำนวนไฟล์และไดเรกทอรีทั้งหมดในระบบซึ่งไม่เกี่ยวข้องกับคำถามที่ถามว่า "ฉันจะนับจำนวนไฟล์. c และจำนวนไดเรกทอรีที่มีได้อย่างไร ไฟล์ c ในไดเรกทอรีที่ระบุ " นอกจากนี้ตัวเลขของคุณผิดลองบนตัวอย่างใน OP
terdon

@terdon ขอบคุณสำหรับข้อมูลของคุณ ฉันได้ปรับปรุงคำตอบด้วยคำแนะนำของคุณและคำตอบที่คุณโพสต์ไว้ในไซต์ SE อื่น ๆ สำหรับ$PWDตัวแปร: unix.stackexchange.com/a/188191/200094
WinEunuuchs2Unix

1
ตอนนี้คุณต้องแน่ใจว่า$PWDไม่มีตัวละครที่อาจจะพิเศษใน regex
muru
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.