Đếm các tệp trong một thư mục theo phần mở rộng


15

Với mục đích thử nghiệm, tôi muốn đếm xem có bao nhiêu tệp hình ảnh trong một thư mục, phân tách từng loại tệp hình ảnh bằng phần mở rộng tệp (jpg = "yes". Điều này bởi vì sau này nó sẽ hữu ích cho một tập lệnh khác sẽ thực thi một hành động trên mỗi phần mở rộng tập tin). Tôi có thể sử dụng cái gì đó như sau chỉ cho các tệp JPEG không?

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

Xem xét các phần mở rộng tập tin jpg, png, bmp, raw và những người khác, tôi có nên sử dụng một whilechu kỳ để làm điều này?

Câu trả lời:


14

Tôi muốn đề xuất một cách tiếp cận khác, tránh các vấn đề tách từ có thể có của 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

Bạn có thể lặp qua filesmảng với bất kỳ lệnh nào khác mà bạn muốn thực hiện trên các tệp của từng tiện ích mở rộng cụ thể.


Đáng tin cậy hơn - hoặc cho các shell không cung cấp mảng rõ ràng - bạn có thể sử dụng lại mảng tham số vị trí của shell tức là

set -- *."$ext"

và sau đó thay thế ${#files[@]}${files[@]}với $#"$@"


23

Cách tiếp cận của tôi sẽ là:

  1. Liệt kê tất cả các tập tin trong thư mục
  2. Trích xuất phần mở rộng của họ
  3. Sắp xếp kết quả
  4. Đếm số lần xuất hiện của mỗi phần mở rộng

Sắp xếp như thế này ( awkcuộc gọi cuối cùng hoàn toàn để định dạng):

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

(giả sử GNU lsở đây cho -Utùy chọn bỏ qua việc sắp xếp dưới dạng tối ưu hóa. Nó có thể được gỡ bỏ một cách an toàn mà không ảnh hưởng đến chức năng nếu không được hỗ trợ).


mhmh ... sau này tôi có nên lọc từng phần mở rộng được tìm thấy để thực hiện một hành động cho nó không?
watchmansky

Nó phụ thuộc vào những gì bạn muốn làm cuối cùng. Bạn có thể cung cấp thêm thông tin?
Groxxda

Mục tiêu của tôi: một tập lệnh xử lý từng tệp mở rộng (chỉ tệp hình ảnh) thay đổi kích thước từ dữ liệu người dùng đầu vào. Vì vậy, tôi bắt đầu từ bao nhiêu file jpg đang có, png tiếp theo vv
watchmansky

giải pháp thép có thể thích hợp hơn sau đó.
Groxxda

2
Tôi đã có cả hai JPGjpgcác tập tin, và muốn nó được đệ quy vì vậy giải pháp của tôi là viếtfind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian

11

Điều này đệ quy đi qua các tệp và đếm các phần mở rộng phù hợp:

$ 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

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

3
Đừng quên một thư mục bắt đầu với find. Ngoài ra, nó có thể giúp người đọc trong tương lai của những câu trả lời này nếu bạn đưa ra lời giải thích ngắn gọn về giải pháp của bạn (trong trường hợp họ muốn sửa đổi nó cho một trường hợp hơi khác).
Jeff Schaller

Giải pháp này xử lý tốt như thế nào với tên đường dẫn chứa khoảng trắng? Dòng mới?
dhag

1
findmặc định cho thư mục hiện tại, đó là cách tôi sử dụng thư mục này. Tôi không nghĩ rằng Chúa dự định tên tập tin có không gian trong đó, nhưng điều này hoạt động tốt trong trường hợp đó. Nếu bạn có dòng mới, thì bạn xứng đáng với tất cả những gì bạn nhận được. Tôi nghĩ về một lời giải thích nhưng quyết định nó sẽ khiến câu trả lời quá dài, tôi nghĩ sự đơn giản mới là điều quan trọng. 99% các trường hợp trong 1% thời gian. Đây có lẽ là phiên bản 7 tương thích.
Neik

3

Có lẽ nó có thể ngắn hơn

exts=( *.jpg *.png *.gif ); printf "There are ${#exts[@]}" extensions;

3

Bất cứ điều gì liên quan lsđều có khả năng tạo ra kết quả bất ngờ với ký tự đặc biệt (không gian và các biểu tượng khác). Bất kỳ bashism (như mảng) không thể di động. Bất cứ điều gì liên quan while readthường là chậm.

Mặt khác, findRẤT linh hoạt (rất nhiều tùy chọn để lọc), nó có [ít nhất] hai cú pháp không an toàn cho các ký tự đặc biệt ... và nó có tỷ lệ tốt trên thư mục lớn.

Trong ví dụ này, tôi đã sử dụng -inameđể khớp cả tên mở rộng chữ hoa và chữ thường. Tôi cũng đã hạn chế việc -maxdepth 1tôn trọng "trong thư mục hiện tại" của bạn. Thay vì đếm số lượng dòng, trong đó tên tệp có thể bao gồm CR / LF, -print0sẽ in một byte NULL ở cuối mỗi tên tệp ... vì vậy, | tr -d -c "\000" | wc -lviệc đếm chính xác các tệp (byte 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 -ccó thể được thay thế bằng -printf "\000" | wc -choặc thậm chí -printf '\n' | wc -l.


0

chỉ có thể sử dụng ls cho một cái gì đó IMO đơn giản này

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

hoặc là

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

hoặc là

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

-2

Nếu bạn chắc chắn về tiện ích mở rộng, bạn có thể đi với findthích

find *.jpeg | wc -l

cho đến khi ai đó tạo ra touch $'foo\nbar.jpegvà nó được tính hai lần thay vì một lần. Hoặc tệ hơn, ai đó làmmkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.