นับจำนวนไฟล์ในไดเรกทอรีตามนามสกุล


15

เพื่อวัตถุประสงค์ในการทดสอบฉันต้องการนับจำนวนไฟล์ภาพที่อยู่ในไดเรกทอรีโดยแยกไฟล์ภาพแต่ละประเภทตามนามสกุลไฟล์ (jpg = "ใช่" เพราะในภายหลังจะมีประโยชน์สำหรับสคริปต์อื่นที่จะเรียกใช้การกระทำ ในแต่ละไฟล์นามสกุล) ฉันสามารถใช้สิ่งต่อไปนี้สำหรับไฟล์ JPEG เท่านั้น

jpg=""
count=`ls -1 *.jpg 2>/dev/null | wc -l`
if [ $count != 0 ]
then
echo jpg files found: $count ; jpg="yes"
fi

พิจารณานามสกุลไฟล์ jpg, png, bmp, raw และอื่น ๆ ฉันควรใช้whileวงจรเพื่อทำสิ่งนี้หรือไม่?

คำตอบ:


14

ฉันขอแนะนำวิธีการอื่นหลีกเลี่ยงปัญหาการแยกคำที่เป็นไปได้ ls

#!/bin/bash

shopt -s nullglob

for ext in jpg png gif; do 
  files=( *."$ext" )
  printf 'number of %s files: %d\n' "$ext" "${#files[@]}"

  # now we can loop over all the files having the current extension
  for f in "${files[@]}"; do
    # anything else you like with these files
    :
  done 

done

คุณสามารถวนซ้ำfilesอาร์เรย์ด้วยคำสั่งอื่น ๆ ที่คุณต้องการดำเนินการกับไฟล์ของส่วนขยายเฉพาะแต่ละรายการ


สามารถพกพาได้มากกว่า - หรือสำหรับเชลล์ที่ไม่มีอาเรย์อย่างชัดเจน - คุณสามารถใช้อาเรย์ตำแหน่งพารามิเตอร์ของเชลล์ได้เช่น

set -- *."$ext"

แล้วแทนที่${#files[@]}และ${files[@]}ด้วย$#และ"$@"


23

แนวทางของฉันจะเป็น:

  1. รายการไฟล์ทั้งหมดในไดเรกทอรี
  2. แยกส่วนขยายของพวกเขา
  3. เรียงลำดับผลลัพธ์
  4. นับการเกิดขึ้นของแต่ละส่วนขยาย

ประเภทของสิ่งนี้ (การawkโทรครั้งสุดท้ายสำหรับการจัดรูปแบบล้วนๆ):

ls -q -U | awk -F . '{print $NF}' | sort | uniq -c | awk '{print $2,$1}'

(สมมติว่า GNU มาlsที่นี่เพื่อดู-Uตัวเลือกในการข้ามการเรียงลำดับเป็นการเพิ่มประสิทธิภาพสามารถลบออกได้อย่างปลอดภัยโดยไม่กระทบต่อการทำงานหากไม่รองรับ)


mhmh ... ในภายหลังฉันควรกรองส่วนขยายแต่ละรายการที่พบเพื่อทำการกระทำหรือไม่
watchmansky

ขึ้นอยู่กับสิ่งที่คุณต้องการจะทำในท้ายที่สุด คุณสามารถให้ข้อมูลเพิ่มเติมได้หรือไม่
groxxda

เป้าหมายของฉัน: สคริปต์ที่ประมวลผลไฟล์ส่วนขยายแต่ละไฟล์ (เฉพาะไฟล์รูปภาพ) เปลี่ยนขนาดจากข้อมูลผู้ใช้ที่ป้อนเข้า ดังนั้นฉันเริ่มจากจำนวนไฟล์ jpg ที่นั่น png ถัดไป ฯลฯ
watchmansky

วิธีการแก้ปัญหา steeldrivers อาจจะเหมาะสมกว่านั้น
groxxda

2
ผมมีทั้งสองJPGและjpgไฟล์และอยากให้มันซ้ำเพื่อแก้ปัญหาของฉันคือการเขียนfind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian

11

การวนซ้ำนี้จะสำรวจไฟล์และนับส่วนขยายที่ตรงกัน:

$ find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'
   6 tiff
   7 bmp
  26 jpeg
  38 gif
  51 jpg
  54 png

6
find -type f | sed -e 's/.*\.//' | sort | uniq -c

3
findอย่าลืมไดเรกทอรีที่เริ่มต้นด้วย นอกจากนี้ยังสามารถช่วยผู้อ่านในอนาคตของคำตอบเหล่านี้หากคุณให้คำอธิบายสั้น ๆ เกี่ยวกับโซลูชันของคุณ (ในกรณีที่พวกเขาต้องการแก้ไขสำหรับกรณีที่แตกต่างกันเล็กน้อย)
Jeff Schaller

โซลูชันนี้จัดการกับชื่อพา ธ ที่มีช่องว่างได้ดีเพียงใด การขึ้นบรรทัดใหม่?
dhag

1
findเริ่มต้นไปที่ไดเรกทอรีปัจจุบันซึ่งเป็นวิธีที่ฉันใช้นี้ ฉันไม่คิดว่าพระเจ้าทรงตั้งชื่อไฟล์ให้มีช่องว่างในตัว แต่สิ่งนี้ใช้ได้ดีสำหรับกรณีนั้น หากคุณมีการขึ้นบรรทัดใหม่คุณควรได้รับทุกสิ่ง ฉันคิดเกี่ยวกับคำอธิบาย แต่ตัดสินใจว่าจะทำให้คำตอบยาวเกินไปฉันคิดว่าความเรียบง่ายเป็นเรื่องสำคัญ 99% ของคดีใน 1% ของเวลา นี่อาจเป็นเวอร์ชั่นที่เข้ากันได้ 7
Neik


3

สิ่งใดที่เกี่ยวข้องกับlsการสร้างผลลัพธ์ที่ไม่คาดคิดด้วยตัวอักษรพิเศษ ความนิยมใด ๆ (เช่นอาร์เรย์) ไม่สามารถเคลื่อนย้ายได้ อะไรก็ได้ที่เกี่ยวข้องwhile readมักจะช้า

ในอีกทางหนึ่งfindมีความยืดหยุ่นมาก (ตัวเลือกมากมายสำหรับตัวกรอง) มันมี [อย่างน้อย] สองไวยากรณ์ที่ไม่ปลอดภัยสำหรับตัวอักษรพิเศษ ... และปรับขนาดได้ดีในไดเรกทอรีขนาดใหญ่

สำหรับตัวอย่างนี้ฉันใช้-inameเพื่อจับคู่ชื่อส่วนขยายตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ฉันยัง จำกัด ที่-maxdepth 1จะเคารพคำถามของคุณ "ในไดเรกทอรีปัจจุบัน" แทนที่จะนับจำนวนบรรทัดที่ชื่อไฟล์อาจรวมถึง CR / LF -print0จะพิมพ์ NULL ไบต์ที่ส่วนท้ายของชื่อไฟล์แต่ละไฟล์ ... ดังนั้นการ| tr -d -c "\000" | wc -lนับจำนวนไฟล์อย่างแม่นยำ (NULL ไบต์!)

extensions="jpg png gif"
for ext in $extensions; do
  c=$(find . -maxdepth 1 -iname "*.$ext" -print0 | tr -d -c "\000" | wc -c)
  if [ $c -gt 0 ]; then
    echo "Found $c  *.$ext files"

    find . -maxdepth 1 -iname "*.$ext" -print0 | xargs -0 -r -n1 DOSOMETHINGHERE
    # or #  find . -maxdepth 1 -iname "*.$ext" -exec "ls" "-l" "{}" ";"
  fi
done

PS -print0 | tr -d -c "\000" | wc -cสามารถถูกแทนที่ด้วยหรือแม้กระทั่ง-printf "\000" | wc -c-printf '\n' | wc -l


0

สามารถใช้ ls เพื่ออะไรบางอย่างที่ IMO ง่าย ๆ นี้ได้

ls -l /opt/ssl/certs/*.pem | wc -l

หรือ

count=$(ls -l /some/folder/*.jpg | wc -l)

หรือ

ls *.{mp3,exe,mp4} 2>/dev/null | wc -l

-2

หากคุณแน่ใจในส่วนขยายคุณสามารถไปกับfindlike

find *.jpeg | wc -l

จนกว่าจะมีใครสร้างtouch $'foo\nbar.jpegและมันจะถูกนับสองครั้งแทนที่จะเป็นครั้งเดียว หรือแย่กว่านั้นคือมีคนทำmkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.