tìm kiếm không phân biệt chữ hoa chữ thường


17

Tôi có cách nào để tìm tất cả các tệp trong một thư mục có tên tệp trùng lặp, bất kể vỏ (chữ hoa và / hoặc chữ thường) không?

Câu trả lời:


14

Nếu bạn có các tiện ích GNU (hoặc ít nhất là một bộ có thể xử lý các dòng kết thúc bằng 0), một câu trả lời khác có một phương pháp tuyệt vời:

find . -maxdepth 1 -print0 | sort -z | uniq -diz

Lưu ý: đầu ra sẽ có các chuỗi kết thúc bằng không; công cụ bạn sử dụng để tiếp tục xử lý nó sẽ có thể xử lý việc đó.

Trong trường hợp không có các công cụ xử lý các dòng kết thúc bằng 0 hoặc nếu bạn muốn đảm bảo mã của bạn hoạt động trong môi trường không có các công cụ đó, bạn cần một tập lệnh nhỏ:

#!/bin/sh
for f in *; do
  find . -maxdepth 1 -iname ./"$f" -exec echo \; | wc -l | while read count; do
    [ $count -gt 1 ] && echo $f
  done
done

Sự điên rồ này là gì? Xem câu trả lời này để được giải thích về các kỹ thuật làm cho điều này an toàn cho tên tập tin điên.


1
Tôi vừa mới đăng một bài tương tự ... Nhưng câu trả lời tệ hơn :)
rozcietrzewiacz

2
Bạn có thực sự cần -mindepthcủa?
rozcietrzewiacz

Tôi đang sử dụng Solaris. Là / usr / bin / tìm người bạn đang nói đến? Tôi đã thử sử dụng nó và cho tôi nhiều lỗi.
lamcro

@lamcro Không, Solaris không sử dụng GNU find; Tôi đã chỉnh sửa câu trả lời để bao gồm một giải pháp không phải GNU.
Shawn J. Goff

Đồng ý. Tôi chỉ cần dán nó vào một tệp văn bản và cung cấp cho nó quyền thực thi?
lamcro

12

Có nhiều câu trả lời phức tạp ở trên, điều này có vẻ đơn giản và nhanh hơn tất cả chúng:

find . -maxdepth 1 | sort -f | uniq -di

Nếu bạn muốn tìm tên tệp trùng lặp trong thư mục con thì bạn cần so sánh chỉ tên tệp chứ không phải toàn bộ đường dẫn:

find . -maxdepth 2 -printf "%f\n" | sort -f | uniq -di

Chỉnh sửa: Shawn J. Goff đã chỉ ra rằng điều này sẽ thất bại nếu bạn có tên tệp với các ký tự dòng mới. Nếu bạn đang sử dụng các tiện ích GNU, bạn cũng có thể làm cho các công cụ này hoạt động:

find . -maxdepth 1 -print0 | sort -fz | uniq -diz

Các -print0(ví find) và -ztùy chọn (đối với sắp xếp và uniq) làm cho chúng hoạt động trên dây NUL-chấm dứt, thay vì xuống dòng chấm dứt chuỗi. Vì tên tệp không thể chứa NUL, nên tên này hoạt động với tất cả các tên tệp.


1
Nhưng hãy xem nhận xét của tôi về câu trả lời của Shawn J. Goff, bạn có thể thêm tùy chọn -print0 để tìm và tùy chọn -z cho uniq và sắp xếp. Ngoài ra, bạn muốn -f trên sắp xếp là tốt. Sau đó, nó hoạt động. (Tôi sẽ chỉnh sửa câu trả lời này thành câu trả lời của bạn, vui lòng hoàn nguyên nếu bạn không chấp thuận)
derobert

Lệnh cuối cùng là cho tôi đầu ra mà không trả về vận chuyển (kết quả là tất cả trong một dòng). Tôi đang sử dụng Red Hat Linux để chạy lệnh. Dòng lệnh đầu tiên hoạt động tốt nhất cho tôi.
CN

2

Sắp xếp danh sách các tên tệp theo cách không phân biệt chữ hoa chữ thường và in các bản sao. sortcó một tùy chọn để phân loại không phân biệt chữ hoa chữ thường. GNU cũng vậy uniq, nhưng không phải các triển khai khác và tất cả những gì bạn có thể làm uniqlà in mọi phần tử trong một tập hợp trùng lặp ngoại trừ lần đầu tiên gặp phải. Với các công cụ GNU, giả sử rằng không có tên tệp nào chứa dòng mới, có một cách dễ dàng để in tất cả các phần tử nhưng một trong mỗi bộ trùng lặp:

for x in *; do printf "%s\n" "$x"; done |
sort -f |
uniq -id

Có thể, để in tất cả các thành phần trong mỗi bộ trùng lặp, giả sử rằng không có tên tệp nào chứa dòng mới:

for x in *; do printf "%s\n" "$x"; done |
sort -f |
awk '
    tolower($0) == tolower(prev) {
        print prev;
        while (tolower($0) == tolower(prev)) {print; getline}
    }
    1 { prev = $0 }'

Nếu bạn cần chứa tên tệp chứa dòng mới, hãy tìm Perl hoặc Python. Lưu ý rằng bạn có thể cần phải điều chỉnh đầu ra hoặc tốt hơn là xử lý thêm bằng cùng một ngôn ngữ, vì mã mẫu bên dưới sử dụng dòng mới để phân tách tên trong đầu ra của chính nó.

perl -e '
    foreach (glob("*")) {push @{$f{lc($_)}}, $_}
    foreach (keys %f) {@names = @{$f{$_}}; if (@names > 1) {print "$_\n" foreach @names}}
'

Đây là một giải pháp zsh thuần túy. Đó là một chút dài dòng, vì không có cách tích hợp nào để giữ các phần tử trùng lặp trong một kết quả toàn cầu hoặc mảng.

a=(*)(N); a=("${(@io)a}")
[[ $#a -le 1 ]] ||
for i in {2..$#a}; do
  if [[ ${(L)a[$i]} == ${(L)a[$((i-1))]} ]]; then
    [[ ${(L)a[$i-2]} == ${(L)a[$((i-1))]} ]] || print -r $a[$((i-1))]
    print -r $a[$i]
  fi
done

1

Không có GNU find:

LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'


2
trrất có khả năng tàn phá trên bất kỳ bộ ký tự trong đó sử dụng nhiều hơn một byte duy nhất cho mỗi nhân vật. Chỉ 256 ký tự đầu tiên của UTF-8 là an toàn khi sử dụng tr. Từ Wikipedia tr (Unix) .. Hầu hết các phiên bản tr, bao gồm GNU trvà Unix cổ điển tr, hoạt động trên SINGLE BYTES và không tuân thủ Unicode ..
Peter.O

1
Cập nhật nhận xét trước đây của tôi .. chỉ 128 ký tự đầu tiên của UTF-8 là an toàn. Tất cả các ký tự UTF-8 trên phạm vi thứ tự 0..127 đều là nhiều byte và có thể có các giá trị byte riêng lẻ trong các ký tự khác. Chỉ các byte trong phạm vi 0..127 có liên kết một-một với một ký tự duy nhất.
Peter.O

Plus uniqcó cờ không phân biệt chữ hoa chữ thường i.
Jamie Kitson

1

Cuối cùng tôi đã quản lý nó theo cách này:

find . | tr '[:upper:]' '[:lower:]' | sort | uniq -d

Tôi đã sử dụng findthay vì vì lstôi cần đường dẫn đầy đủ (rất nhiều thư mục con) đi kèm. Tôi không tìm thấy làm thế nào để làm điều này với ls.


2
Cả hai sortuniqcó cờ bỏ qua, f và i tương ứng.
Jamie Kitson

-1

Đối với bất kỳ ai khác muốn đổi tên, v.v ... một trong các tệp:

find . -maxdepth 1 | sort -f | uniq -di | while read f; do echo mv "$f" "${f/.txt/_.txt}"; done
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.