중복된 파일 이름에 대해 대소문자를 구분하지 않고 검색

중복된 파일 이름에 대해 대소문자를 구분하지 않고 검색

대소문자(대문자 및/또는 소문자)에 관계없이 중복된 파일 이름이 있는 디렉터리의 모든 파일을 찾을 수 있는 방법이 있습니까?

답변1

사용 가능한 GNU 유틸리티가 있는 경우(또는 최소한 0으로 끝나는 줄을 처리할 수 있는 세트)또 다른 대답좋은 방법이 있습니다:

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

참고: 출력에는 0으로 끝나는 문자열이 있습니다. 추가 처리에 사용하는 도구는 이를 처리할 수 있어야 합니다.

0으로 끝나는 줄을 처리하기 위한 도구가 없거나 이러한 도구를 사용할 수 없는 환경에서 코드가 작동하는지 확인하려면 다음과 같은 작은 스크립트가 필요합니다.

#!/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

이 광기는 무엇입니까? 바라보다이 답변이상한 파일 이름을 안전하게 만드는 기술에 대한 설명입니다.

답변2

위에는 복잡한 답변이 많이 있습니다. 이는 모든 답변보다 간단하고 빠릅니다.

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

하위 디렉터리에서 중복된 파일 이름을 찾으려면 전체 경로가 아닌 파일 이름만 비교해야 합니다.

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

편집자: Shawn J. Goff는 파일 이름에 개행 문자가 있으면 이것이 실패할 것이라고 지적했습니다. GNU 유틸리티를 사용하면 다음 작업도 수행할 수 있습니다.

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

-print0(찾기용) 및 옵션 -z(정렬 및 uniq용)을 사용하면 줄바꿈으로 끝나는 문자열 대신 NUL로 끝나는 문자열에서 작동합니다. 파일 이름에는 NUL을 포함할 수 없으므로 이는 모든 파일 이름에 적용됩니다.

답변3

파일 이름 목록을 대소문자를 구분하지 않고 정렬하고 중복 항목을 인쇄합니다. sort대소문자를 구분하지 않는 정렬 옵션이 있습니다. GNU에서도 마찬가지 uniq지만, 다른 구현에서는 그렇지 않습니다. 여기서 할 수 있는 일은 uniq처음 발견된 요소를 제외하고 중복된 요소 집합의 모든 요소를 ​​인쇄하는 것뿐입니다. 파일 이름에 줄 바꿈이 포함되어 있지 않다고 가정하고 GNU 도구를 사용하면 각 중복 세트 중 하나만 제외하고 모두 인쇄하는 간단한 방법이 있습니다.

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

이식 가능한 파일 이름에 줄 바꿈이 포함되어 있지 않다고 가정하여 각 중복 세트의 모든 요소를 ​​인쇄하려면 다음을 수행하십시오.

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 }'

줄 바꿈이 포함된 파일 이름을 수용해야 하는 경우 Perl 또는 Python을 사용하십시오. 아래 예제 코드에서는 출력에서 ​​이름을 구분하기 위해 개행 문자를 사용하므로 출력을 조정해야 하거나 추가 처리를 위해 동일한 언어를 사용하는 것이 더 나을 수도 있습니다.

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

이것은 순수한 zsh 솔루션입니다. 배열이나 전역 결과에 중복 요소를 유지하는 기본 제공 방법이 없기 때문에 다소 장황합니다.

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

답변4

GNU 없이 find:

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

관련 정보