วิธีใช้ wc และ piping เพื่อค้นหาว่ามีไฟล์และไดเรคทอรีจำนวนเท่าใดในไดเรกทอรีหนึ่ง


10

ฉันจะใช้ตัวนับคำ ( wc) และการไพพ์เพื่อนับจำนวนไฟล์หรือไดเรกทอรีที่อยู่ใน/usr/binไดเรกทอรีได้อย่างไร


การบ้านนี้ ?? ไม่เป็นไรที่จะขอความช่วยเหลือเพียงระบุว่าเป็นเช่นนั้น
slm

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

ls / bin / usr / bin | จัดเรียง | uniq | wc -
เงินสด

NP การขอความช่วยเหลืออย่างสมบูรณ์แบบนั้นดีมาก! เพียงติดป้ายเพื่อให้ผู้คนรู้ว่าทุกคนที่นี่มีความสุขที่จะช่วยเหลือผู้ที่พยายามเรียนรู้จุดที่ดีกว่าของ Unix
slm

คำตอบ:


13

วิธีการหนึ่งที่จะใช้ประโยชน์จากlsการให้รายการของไฟล์กับเรา แต่เราต้องการให้รายการนี้รับประกันว่าจะแสดงเพียง 1 ไฟล์หรือไดเรกทอรีต่อบรรทัด -1สวิทช์จะทำเช่นนี้สำหรับเรา

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

ตัวอย่าง

สร้างข้อมูลตัวอย่างข้างต้นในไดเรกทอรีว่าง

$ mkdir dir{1..3}
$ touch file{A..C}

ตรวจสอบ:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

ตอนนี้เพื่อนับคุณสามารถใช้wc -lเพื่อนับจำนวนบรรทัดซึ่งสอดคล้องกับไฟล์หรือไดเรกทอรีในls -1ผลลัพธ์

$ ls -1 | wc -l
6

(โปรดทราบว่าไม่รวมไฟล์ที่ซ่อนอยู่)

การนับไฟล์หรือไดเรกทอรีไม่ได้อยู่ด้วยกัน

ในการนับไฟล์หรือไดเรกทอรีคุณต้องเปลี่ยนชั้นเชิงเล็กน้อย ในกรณีนี้ฉันจะใช้ls -lเนื่องจากมันแสดงว่าเป็นไดเรกทอรีอะไรและไฟล์ aa

ตัวอย่าง

$ ls -l
total 12
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

จากนั้นเราสามารถใช้grepเพื่อกรองไดเรกทอรีหรือไดเรกทอรีที่ไม่ชอบ:

# directories
$ ls -l | grep "^d"
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3

# regular files
$ ls -l | grep "^-"
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

ตอนนี้ใช้wc -lอีกครั้งเพื่อนับจำนวนข้างต้น:

# directories
$ ls -l | grep "^d" | wc -l
3

# regular files
$ ls -l | grep "^-" | wc -l
3

แม้ว่าคุณสามารถหลีกเลี่ยงwcโดยสิ้นเชิงและการใช้งานgrepของ-cตัวเลือก:

$ ls -l | grep -c '^d'

(อีกครั้งไฟล์ที่ซ่อนจะไม่รวมโปรดทราบว่าไดเรกทอรีและปกติเป็นไฟล์สองประเภทมีหลายอย่างเช่นเนมไปป์ลิงก์สัญลักษณ์อุปกรณ์ซ็อกเก็ต ... )

recursion

หากคุณต้องการที่จะหาไฟล์และไดเรกทอรีซ้ำภายใต้แล้วคุณอาจจะต้องการที่จะใช้กลยุทธ์การเปลี่ยนแปลงอย่างสิ้นเชิงและทำให้การใช้เครื่องมือที่เรียกว่า/usr/binfind

ตัวอย่าง

$ find /usr/bin | wc -l
4632

(แม้ว่าข้างบน/usr/binจะรวมอยู่ในการนับ)

เทคนิคเดียวกับที่ฉันใช้ข้างต้นอาจใช้lsเพื่อทำสิ่งที่คล้ายกัน แต่lsโดยทั่วไปแล้วไม่ใช่เครื่องมือที่ดีในการแยกวิเคราะห์ผลลัพธ์ findในทางตรงกันข้ามถูกสร้างขึ้นสำหรับสิ่งนี้และมีสวิตช์เพื่อค้นหาไฟล์หรือไดเรกทอรี

# find files
$ find /usr/bin -type f

# find directories
$ find /usr/bin -type d

(โปรดทราบว่าเวลาfindนี้รวมถึงไฟล์ที่ซ่อนอยู่ (ยกเว้น.และ..))

การขึ้นบรรทัดใหม่?

ฉันไม่เคยเข้าใจเลยว่าทำไมอักขระขึ้นบรรทัดใหม่เป็นอักขระถูกกฎหมายที่จะใช้เมื่อสร้างชื่อไฟล์หรือชื่อไดเรกทอรี ดังนั้นวิธีการที่กล่าวถึงข้างต้นโดยใช้wcและlsจะไม่โต้แย้งกับสิ่งเหล่านี้ดังนั้นให้ใช้กับสิ่งที่อยู่ในใจ

ตัวอย่าง

สร้างไดเรกทอรีและชื่อไฟล์ด้วยการขึ้นบรรทัดใหม่

$ mkdir $'dir4\n5'
$ touch $'fileD\nE'

ls แสดงอย่างถูกต้อง:

$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E

แต่wcจะนับไดเรกทอรีและไฟล์ที่มีบรรทัดใหม่เป็น 2 รายการไม่ใช่หนึ่งรายการ

$ ls -1 | wc -l
10

วิธีหนึ่งในการหลีกเลี่ยงปัญหานี้หากใช้การนำ GNU ไปใช้findคือใช้findความสามารถในการพิมพ์อย่างอื่นแทนไฟล์แต่ละไฟล์ที่พบแล้วนับจำนวนนั้นแทน

ตัวอย่าง

$ find . -printf . | wc -c
9

นี่เรากำลังค้นหาทุกอย่างในไดเรกทอรีปัจจุบัน (ยกเว้น..) และพิมพ์จุด ( .) สำหรับแต่ละและจากนั้นนับจุดโดยใช้ความสามารถที่จะนับไบต์แทนสาย,wcwc -c

อ้างอิง


ในขณะที่ไฟล์ใน/usr/binทุกรูปแบบจะมีรูปแบบที่ดี (และยังไม่มีช่องว่างดังนั้นในทางเทคนิคคุณสามารถทำได้echo * | wc -w) มันก็คุ้มค่าที่จะสังเกตว่าสิ่งเหล่านี้ทั้งหมดจะแตกในชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่
evilsoup

@evilsoup - ไม่ฉันไม่เชื่อls -lหรือls -1จะทำลาย b / c เรากำลังนับบรรทัดไม่ใช่คำพูด! findอาจแบ่งอีกครั้ง แต่เรานับเส้นไม่ได้คำ
slm

สิ่งที่ฉันหมายความว่านี้จะ (ฉันคิดว่าฉันบน Windows ในขณะนี้ดังนั้นฉันสามารถทดสอบได้) ถ้าแบ่งไฟล์ที่มีการขึ้นบรรทัดใหม่ ดังนั้นtouch $'foo\nbar'ภายในไดเรกทอรีว่างแล้วตามด้วยหนึ่งในคำสั่งของคุณ (พูดls -1 | wc -l) จะรายงานสองไฟล์มากกว่าหนึ่ง - เพราะไฟล์นั้นมีสองบรรทัดเท่าที่wcเกี่ยวข้อง ยกเว้นการขึ้นlsบรรทัดใหม่ด้วยอักขระอื่น (ฉันไม่คิดว่ามันจะเป็นเช่นนั้น แต่อีกครั้งฉันไม่สามารถทดสอบได้ในตอนนี้)
evilsoup

@evilsoup - แก้ไขอักขระขึ้นบรรทัดใหม่ เป็นนักกฎหมาย สำหรับชื่อไฟล์และวิธีการจะไม่สามารถต่อสู้กับชื่อไฟล์ประเภทเหล่านั้นได้อย่างถูกต้อง
slm

@StephaneChazelas - เป็นwc -cปัญหาเมื่อนับจำนวนงวดหรือไม่
slm

5

หากคุณต้องการทำลายจำนวนไฟล์แต่ละประเภทซ้ำ ๆ ภายใต้ dir บางอันด้วย GNU findคุณสามารถทำได้:

find /some/dir/. ! -name . -printf '%y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

เปิด/usr/binในระบบของฉันซึ่งให้:

   3727 regular files
    710 symbolic links

เปิด/dev:

     83 block devices
    203 character devices
     31 directories
    426 symbolic links
      1 FIFOs
      1 Unix domain sockets

สำหรับ symlink หากคุณต้องการนับเป็นประเภทของไฟล์ที่ชี้ไปมากกว่าsymbolic linksคุณสามารถเปลี่ยนเป็น:

find /some/dir/. ! -name . -printf '%Y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/N/broken symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

ซึ่งตอนนี้ให้สำหรับฉัน/usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(symlink ที่ใช้งานไม่ได้คือ symlink ไปยังไฟล์ซึ่งfindไม่สามารถระบุประเภทได้เนื่องจากไฟล์ไม่มีอยู่หรืออยู่ในไดเรกทอรีที่คุณไม่สามารถเข้าถึงหรือมีลูปในการแก้ไขเส้นทางของไฟล์ ในกรณีของฉันทั้งสองที่ symlink ไปยังไฟล์ที่หายไป)

ไม่นับผู้ที่และ. ..หากคุณต้องการให้พวกเขารวม (ทำไมคุณจะ?) ไม่มีวิธีอื่นที่มีfindกว่าสมมติว่าพวกเขามีสำหรับทุกไดเรกทอรีและนับพวกเขาอย่างเป็นระบบ:

find /some/dir/. -printf '%y\n' \( -name . -printf 'd\n' -o \
  -type d -printf 'd\nd\n' \)  | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

ซึ่งให้กับฉันแล้ว/usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

หากคุณไม่สามารถเข้าถึง GNU findคุณสามารถเขียนใหม่เป็น:

find /some/dir/. ! -name . \( \
  -type f -exec printf '%.0sregular files\n' {} + -o \
  -type d -exec printf '%.0sdirectories\n' {} + -o \
  -type l -exec printf '%.0ssymbolic links\n' {} + -o \
  -type s -exec printf '%.0sUnix domain sockets\n' {} + -o \
  -type b -exec printf '%.0sblock devices\n' {} + -o \
  -type c -exec printf '%.0scharacter devices\n' {} + -o \
  -type p -exec printf '%.0sFIFOs\n' {} + -o \
  -exec printf '%.0sothers\n' {} + \) | sort | uniq -c

ตอนนี้อย่างเคร่งครัดพูดเราไม่ได้รับการนับไฟล์แต่รายการไดเรกทอรี ไดเรกทอรีเช่น/usr/binโดยทั่วไปมีหลายรายการที่ชี้ไปที่ไฟล์เดียวกัน ตัวอย่างเช่นที่นี่ฉันมี:

$ ls -lid /usr/bin/{nvi,nview,nex}
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nex
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nvi
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nview

รายการเหล่านี้คือ 3 รายการไดเรกทอรี (ชื่อไฟล์หรือที่รู้จักกันว่าฮาร์ดลิงก์) ไปยังไฟล์เดียวกัน (รายการที่มี inode 672252 หากต้องการนับไฟล์แทนรายการไดเรกทอรีและด้วย GNU findและ GNU uniq(ไม่สนใจ.และ..ไฟล์ซึ่งเป็นลิงก์ไปยังไดเรกทอรีอื่น ๆ ):

find /some/dir/. ! -name . -printf '%y\t%D:%i\n' |
  sort -u |
  cut -f1 |
  uniq -c |
  sed '
    s/f/regular files/;t
    s/d/directories/;t
    s/l/symbolic links/;t
    s/s/Unix domain sockets/;t
    s/b/block devices/;t
    s/c/character devices/;t
    s/p/FIFOs/;t
    s/d/Doors/;t
    s/n/network special files/;t
    s/.$/others (&)/'

บนของฉัน/usr/binที่ให้:

   3711 regular files
    710 symbolic links

0

คุณไม่ได้พูดว่าถ้าคุณต้องการไฟล์ทั้งหมดภายใต้ / usr / bin ซ้ำหรือเพียงแค่อยู่ในระดับแรก นอกจากนี้คุณจะได้คำที่คุณนับได้อย่างไร วิธีปกติในการค้นหาคือใช้ find ใน wc ดังนี้: find / usr / bin | wc -l ค้นหาจะแสดงรายการทุกสิ่งที่นั่นไดเรกทอรีและไฟล์ Wc -l จะนับบรรทัดทั้งหมดใน find output นี่คือการมอบหมายชั้นเรียนหรือไม่? มันก็โอเคถ้าเป็น แต่ฉันสงสัยว่าทำไมคุณถึงต้องการข้อมูลนี้เพื่อที่ฉันจะได้ปรับการตอบสนองให้ดีขึ้น โปรดแจ้งให้เราทราบหากคุณต้องการเพิ่มเติม คอสตา


0

ในทุบตีโดยไม่ต้องใช้เครื่องมือภายนอก

cd dir/ || exit; shopt -s nullglob; shopt -s dotglob; count=(*); echo "${#count}"

ในทุบตีโดยไม่ต้องใช้เครื่องมือภายนอกและการเรียกซ้ำ

shopt -s globstar; shopt -s dotglob 
for dir in **/*/; do 
  unset d f
  for files in "$dir"*; do 
    [[ -f $files ]] && ((++f))
    [[ -d $files ]] && ((++d))
  done; 
  printf '%s\n' "$dir -  files: ${f:-0} - directories: ${d:-0}"
done

โปรดทราบว่าตัวที่สองจะติดตาม symlinks เมื่อเรียกใช้ซ้ำ (และนับ symlink ให้กับไฟล์ปกติเป็นไฟล์ปกติและ symlink ไปยัง dirs ในฐานะ dirs) จะไม่นับจำนวนไฟล์และไดเรกทอรีในไดเรกทอรีปัจจุบันและจะไม่นับ.หรือ..รายการ คุณอาจต้องการแปลงไฟล์เป็นไฟล์ปกติ
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.