Thư mục có hai hoặc nhiều tệp


11

Tôi muốn tìm một thư mục con của thư mục hiện tại, trong đó (đó là thư mục con) chứa 2 hoặc nhiều tệp thông thường.

Tôi không quan tâm đến các thư mục chứa ít hơn 2 tệp, cả trong các thư mục chỉ chứa các thư mục con.

Câu trả lời:


12

Đây là một cách tiếp cận hoàn toàn khác nhau dựa trên GNU finduniq. Điều này nhanh hơn và thân thiện với CPU hơn nhiều so với các câu trả lời dựa trên việc thực hiện lệnh shell đếm các tệp cho mỗi thư mục được tìm thấy.

find . -type f -printf '%h\n' | sort | uniq -d

Các findlệnh in thư mục của tất cả các file trong hệ thống phân cấp và uniqchỉ hiển thị các thư mục xuất hiện ít nhất hai lần.


2
Bạn không nên phân tích đầu ra của find. Trong trường hợp này, vì GNU findsẽ đọc tên của các thư mục có các ký tự không thể in được trong miền địa phương hiện tại (như "ä" trong miền địa phương C). Xem thêm unix.stackexchange.com/questions/321697/iêu
Kusalananda

4
@Kusalananda, không phải khi đầu ra không đi đến một tty. Ở đây, vấn đề duy nhất là với các ký tự dòng mới, bạn có thể khắc phục bằng cách sử dụng-printf '%h\0' | sort -z | uniq -zd | xargs -r0 ...
Stéphane Chazelas

6
find . -type d \
    -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' \
    -print

Điều này sẽ tìm thấy tất cả các tên trong hoặc dưới thư mục hiện tại và sau đó lọc ra tất cả các tên không phải là tên của thư mục.

Các tên thư mục còn lại sẽ được đặt cho tập lệnh ngắn này:

c=0
for n in "$1"/*; do
    [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done

[ "$c" -ge 2 ]

Kịch bản lệnh này sẽ đếm số lượng tệp thông thường (bỏ qua các liên kết tượng trưng) trong thư mục được cung cấp làm đối số dòng lệnh đầu tiên (từ find). Lệnh cuối cùng trong tập lệnh là một bài kiểm tra để xem liệu số đếm là 2 hay lớn hơn. Kết quả của bài kiểm tra này là giá trị trả về (trạng thái thoát) của tập lệnh.

Nếu thử nghiệm thành công, -printsẽ gây ra findviệc in đường dẫn đến thư mục.

Để xem xét các tệp bị ẩn (các tệp có tên bắt đầu bằng dấu chấm), hãy thay đổi sh -ctập lệnh từ nói

for n in "$1"/*; do

đến

for n in "$1"/* "$1"/.*; do

Kiểm tra:

$ tree
.
`-- test
    |-- a
    |-- dir1
    |   |-- a
    |   |-- b
    |   `-- c
    `-- dir2
        |-- dira
        |-- dirb
        |   |-- file-1
        |   `-- file-2
        `-- dirc

6 directories, 6 files

$ find . -type d -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' -print
./test/dir1
./test/dir2/dirb

Giải pháp của bạn không tính các tệp có tên bắt đầu bằng dấu chấm. Bạn cũng nên khởi tạo c = 0 để tránh thông báo lỗi với các thư mục không chứa bất kỳ tệp nào.
xhienne

@xhienne Tôi đã xem xét các tập tin ẩn và sẽ thêm một ghi chú về nó. Không có lỗi nếu không có tệp thông thường trong một thư mục vì đây [ "" -ge 2 ]là một bài kiểm tra hợp lệ.
Kusalananda

Không chắc chắn cách bạn xác định "hợp lệ". POSIX yêu cầu arg1 là một giá trị nguyên. dash, bash --posixtesttất cả hiển thị một thông báo lỗi và thoát ra với 2 (tức là "lỗi Đã xảy ra")
xhienne

@xhienne Ah, tôi đã thử nghiệm trên một hệ thống mà mas kshđang chạy sh. Sẽ sửa đổi ngay lập tức. Cảm ơn đã chọc tôi! :-)
Kusalananda

Ngoài ra, [ -f ... ]các liên kết tượng trưng liên kết. Bạn nên thêm một bài kiểm tra để loại bỏ chúng vì câu hỏi chỉ định rằng chỉ nên tính các tệp thông thường.
xhienne

6

Với sự giúp đỡ của câu trả lời của Gilles về SU và ngược lại và một số sửa đổi, đây là những gì bạn cần.

find . -type d -exec sh -c 'set -- "$1"/*;X=0; 
    for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print

Cây thư mục.

.
├── test
│   ├── dir1
│   │   ├── a
│   │   ├── b
│   │   └── c
│   ├── dir2
│   │   ├── dira
│   │   │   └── a file\012with\012multiple\012line
│   │   ├── dirb
│   │   │   ├── file-1
│   │   │   └── file-2
│   │   └── dirc
│   ├── diraa
│   ├── dirbb
│   ├── dircc
│   └── x
│   └── x1
│   └── x2
└── test2
    ├── dir3
    └── dir4

Kết quả:

./test
./test/dir1
./test/dir2/dirb

Tôi cũng có cái này lúc đầu, nhưng bạn sẽ gặp vấn đề với các thư mục chứa nhiều thư mục con tệp. Nó cũng không loại bỏ các thư mục chỉ chứa các thư mục con.
Kusalananda

Nó không thực sự giải quyết nó. Nó tìm thấy cả testvà các dir2thư mục trong thiết lập thử nghiệm của tôi (xem câu trả lời của tôi).
Kusalananda

Hoạt động cho ví dụ của bạn, nhưng cũng thêm test/x1test/x2dưới dạng tệp ... $1$2sẽ là thư mục cho test, và thư mục sẽ bị bỏ qua.
Kusalananda

@Kusalananda Không có cách nào tôi tìm thấy ngoại trừ những gì bạn trả lời, tôi đã cố gắng thay đổi một phần lệnh của tôi để không trùng lặp chính xác với bạn (tôi không loại trừ các tệp ẩn như bạn đã làm), tôi xin lỗi.
αғsнιη

1
Không phải lo lắng bất cứ điều gì :-)
Kusalananda

3

Cách tiếp cận find+ khác wc:

find path/currdir -maxdepth 1 -type d ! -empty ! -path "path/currdir" \
-exec sh -c 'count=$(find "$1" -maxdepth 1 -type f | wc -l); [ $count -ge 2 ]' _ {} \; -print

  • path/currdir - đường dẫn đến thư mục hiện tại của bạn

  • -maxdepth 1- chỉ xem xét các thư mục con trực tiếp

  • ! -empty - bỏ qua các thư mục con trống

  • ! -path "path/currdir" - bỏ qua đường dẫn thư mục hiện tại

  • count=$(find "$1" -maxdepth 1 -type f | wc -l)- countđược gán với số lượng tệp cho mỗi thư mục con tìm thấy

  • [ $count -ge 2 ] ... -print - in tên / đường dẫn thư mục con chứa 2 hoặc nhiều tệp thông thường

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.