Tìm số lượng tệp cho mỗi phần mở rộng trong một thư mục


10

Tôi muốn đếm số lượng tệp cho mỗi phần mở rộng trong một thư mục cũng như các tệp không có phần mở rộng.

Tôi đã thử một vài lựa chọn, nhưng tôi chưa tìm thấy giải pháp hiệu quả nào:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -clà một tùy chọn nhưng không hoạt động nếu không có phần mở rộng tập tin. Tôi cần biết có bao nhiêu tệp không có phần mở rộng.

  • Tôi cũng đã thử một vòng lặp find thành một mảng và sau đó tổng hợp các kết quả, nhưng tại thời điểm đó, mã đó đưa ra một lỗi biến không được khai báo, nhưng chỉ bên ngoài vòng lặp:

    declare -a arr
    arr=()
    echo ${arr[@]}
    

    Điều này ném một biến không được khai báo, cũng như khi vòng lặp find hoàn thành.

Câu trả lời:


10
find "$path" -type f | sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' | LC_COLLATE=C sort | uniq -c

Giải trình:

  • find "$path" -type f có được một danh sách đệ quy của tất cả các tập tin trên "$path"thư mục.
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' biểu thức chính quy:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ thay thế tất cả các tập tin mà không cần gia hạn bằng (không có).
    • s/.*\.// có được phần mở rộng của các tập tin còn lại.
  • LC_COLLATE=C sort sắp xếp kết quả, giữ các biểu tượng ở trên cùng.
  • uniq -c đếm số lượng các mục lặp đi lặp lại.

9

Sử dụng Python:

import os
from collections import Counter
from pprint import pprint

lst = []
for file in os.listdir('./'):
        name, ext = os.path.splitext(file)
        lst.append(ext)

pprint(Counter(lst))

Đầu ra:

Counter({'': 7,
         '.png': 4,
         '.mp3': 3,
         '.jpg': 3,
         '.mkv': 3,
         '.py': 1,
         '.swp': 1,
         '.sh': 1})

Bạn có thể có thể thoát khỏi việc hiểu danh sách, như ext = [ f.split('.')[-1] for f in os.listdir('./') ] Thatll làm cho nó ngắn hơn vài dòng và có lẽ nhiều Pythonic hơn
Sergiy Kolodyazhnyy

Cảm ơn vì lời đề nghị, tôi chỉ cố gắng viết nó rõ ràng nhất có thể ...
Ravexina

1
Rõ ràng là đức tính :) Đặc biệt khi nói đến mã và tài liệu kỹ thuật.
Sergiy Kolodyazhnyy

6

Nếu bạn có GNU awk, bạn có thể làm một cái gì đó như

printf '%s\0' * | gawk 'BEGIN{RS="\0"; FS="."; OFS="\t"} 
  {a[(NF>1 ? $NF : "(none)")]++} 
  END{for(i in a) print a[i],i}
'

tức là xây dựng / tăng một mảng kết hợp được khóa trên trường được .phân tách cuối cùng hoặc một số chuỗi cố định tùy ý, chẳng hạn như (none)nếu không có phần mở rộng.

mawkdường như không cho phép trình phân tách bản ghi byte null - bạn có thể sử dụng mawkvới trình phân tách dòng mới mặc định nếu bạn tự tin rằng bạn không cần phải xử lý các dòng mới trong tên tệp của mình:

printf '%s\n' * | mawk 'BEGIN{FS="."; OFS="\t"} {a[(NF>1 ? $NF : "(none)")]++} END{for(i in a) print a[i],i}'

5

Với cơ bản /bin/shhoặc thậm chí bashnhiệm vụ có thể hơi khó khăn, nhưng như bạn có thể thấy trong các câu trả lời khác, các công cụ có thể hoạt động trên dữ liệu tổng hợp có thể xử lý công việc đó đặc biệt dễ dàng. Một công cụ như vậy sẽ là sqlitecơ sở dữ liệu.

Quá trình rất đơn giản để sử dụng sqlitecơ sở dữ liệu sẽ là tạo một .csvtệp có hai trường: tên tệp và phần mở rộng. Sau này sqlitecó thể sử dụng câu lệnh tổng hợp đơn giản COUNT()với GROUP BY extđể thực hiện đếm các tệp dựa trên trường mở rộng

$ { printf "file,ext\n"; find -type f -exec sh -c 'f=${1##*/};printf "%s,%s\n" "${1}" "${1##*.}"' sh {} \; ; }  > files.csv
$ sqlite3 <<EOF
> .mode csv
> .import ./files.csv files_tb
> SELECT ext,COUNT(file) FROM files_tb GROUP BY ext;
> EOF
csv,1
mp3,6
txt,1
wav,27

files_tbbảng tôi nghĩ đang được tham chiếu nhưng các cột bảng không được xác định ở bất cứ đâu tôi có thể thấy?
WinEunuuchs2Unix

@ WinEunuuchs2Unix Chúng được định nghĩa trong chính tệp csv. Đó là những gì đầu tiên printflàm. Và SQLite sẽ mặc định xử lý dòng đầu tiên của tệp csv dưới dạng tên cột.
Sergiy Kolodyazhnyy

1
Rất ấn tượng! +1
WinEunuuchs2Unix

5

Sử dụng PowerShell nếu đó là một tùy chọn:

Get-ChildItem -File | Group-Object Extension -NoElement

hoặc ngắn hơn, sử dụng bí danh:

ls -file | group -n Extension

1
Ồ Câu trả lời tuyệt vời đầu tiên! Tôi thậm chí còn không biết PowerShell tồn tại cho Linux ... +1
Fabby

2
Cảm ơn. Nó đã tồn tại đa nền tảng và nguồn mở trong một thời gian, nhưng đã có một mô hình về SO và SU trong đó các câu hỏi về kịch bản shell trên Windows thường được trả lời bằng "Chà, cài đặt cygwin và sử dụng bash, sau đó bạn có thể làm như sau ", Vì vậy, tôi đã do dự khi làm điều tương tự cho các trang web Linux SE với các công cụ có nguồn gốc trên Windows. Nhưng đây là một nhiệm vụ tốt cho thấy sức mạnh của PowerShell khá độc đáo mà không mời các đối số cũ về tính dài dòng.
Joey
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.