重複ファイル名の大文字と小文字を区別せずに検索

重複ファイル名の大文字と小文字を区別せずに検索

大文字と小文字(大文字と小文字)に関係なく、重複したファイル名を持つディレクトリ内のすべてのファイルを見つける方法はありますか?

答え1

利用可能なGNUユーティリティがある場合(または少なくとも0で終わる行を処理できるセット)もう一つの答え良い方法があります:

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

注:出力には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ツールを使用すると、各冗長セットの1つだけを除いてすべてを印刷する簡単な方法があります。

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

関連情報