중복 파일 이름의 대소 문자 구분 검색


17

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

답변:


14

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

이 광기는 무엇입니까? 미친 파일 이름을 안전하게 만드는 기술에 대한 설명은 이 답변 을 참조하십시오 .


1
난 그냥 비슷한 ...하지만 더 나쁜 대답을 :) 게시 거라고
rozcietrzewiacz

2
당신이 정말로 필요 -mindepth합니까?
rozcietrzewiacz

Solaris를 사용하고 있습니다. / usr / bin / find는 당신이 말하는 것입니까? 나는 그것을 사용해 보았고 많은 오류를 주었다.
lamcro

@lamcro 아니요, Solaris는 GNU를 사용하지 않습니다 find. 비 GNU 솔루션을 포함하도록 답변을 편집했습니다.
Shawn J. Goff

확인. 텍스트 파일에 붙여넣고 실행 권한을 부여합니까?
lamcro

12

위의 많은 복잡한 답변이 있습니다. 이것은 모두보다 간단하고 빠릅니다.

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줄 바꿈 문자열을 종료하는 대신, 옵션 그 원인 NUL 종료 문자열에 일에 (종류 및 UNIQ에 대한). 파일 이름은 NUL을 포함 할 수 없으므로 모든 파일 이름에서 작동합니다.


1
그러나 Shawn J. Goff의 답변에 대한 내 의견을 참조하십시오. -print0 옵션을 추가하고 -z 옵션을 사용하여 uniq 및 정렬 할 수 있습니다. 또한 정렬시 -f를 원합니다. 그런 다음 작동합니다. (이 답변을 답변으로 편집하겠습니다. 승인하지 않으면 되돌릴 수 있습니다)
derobert

마지막 명령은 캐리지 리턴없이 출력을 제공합니다 (결과는 모두 한 줄에 있음). Red Hat Linux를 사용하여 명령을 실행하고 있습니다. 첫 번째 명령 줄이 가장 효과적입니다.
일요일

2

대소 문자를 구분하지 않고 파일 이름 목록을 정렬하고 사본을 인쇄하십시오. 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 솔루션입니다. 중복 요소를 배열 또는 glob 결과로 유지하는 기본 제공 방법이 없으므로 조금 장황합니다.

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

GNU없이 find:

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


2
tr이다 매우 문자 당 단일 바이트 이상을 사용하는 모든 문자 집합에 과시의 혼란에 가능성. UTF-8의 처음 256 자만 사용하면 안전 tr합니다. 에서 위키 백과 TR (유닉스) .. 대부분의 버전의 trGNU 포함, tr고전적인 유닉스 tr, SINGLE BYTES에서 작동 및 유니 코드 호환되지 않는 ..
Peter.O

1
이전 의견으로 업데이트하십시오. UTF-8 의 처음 128 자만 안전합니다. 서수 범위 0..127을 초과하는 모든 UTF-8 문자 는 모두 멀티 바이트이며 다른 문자에서 개별 바이트 값을 가질 수 있습니다. 0..127 범위의 바이트 만 고유 문자와 일대일로 연결됩니다.
Peter.O

또한 uniq대소 문자를 구분하지 않는 플래그 i가 있습니다.
Jamie Kitson

1

나는 마침내 이것을 이렇게 관리했다.

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

나는 find대신 ls전체 경로 (많은 하위 디렉토리)가 필요했기 때문에 사용 했습니다 . 이 작업을 수행하는 방법을 찾지 못했습니다 ls.


2
모두 sortuniq각각 무시의 경우 플래그, F와 내가 있습니다.
Jamie Kitson

-1

그런 다음 파일 중 하나의 이름을 바꾸고 싶은 다른 사람들을 위해 :

find . -maxdepth 1 | sort -f | uniq -di | while read f; do echo mv "$f" "${f/.txt/_.txt}"; done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.