Câu trả lời:
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.
-mindepth
của?
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.
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à -z
tù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.
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. sort
có 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 uniq
là 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
Không có GNU find
:
LANG=en_US ls | tr '[A-Z]' '[a-z]' | uniq -c | awk '$1 >= 2 {print $2}'
tr
là rấ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 tr
và Unix cổ điển tr
, hoạt động trên SINGLE BYTES và không tuân thủ Unicode ..
uniq
có cờ không phân biệt chữ hoa chữ thường i.
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 find
thay vì vì ls
tô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
.
sort
và uniq
có cờ bỏ qua, f và i tương ứng.
Đố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