重複するファイル名の大文字と小文字を区別しない検索


17

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

回答:


14

GNUユーティリティ(または少なくともゼロで終了する行を処理できるセット)を使用できる場合、別の答えには素晴らしい方法があります。

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

注:出力には、ゼロで終了する文字列が含まれます。それをさらに処理するために使用するツールは、それを処理できるはずです。

ゼロで終了する行を処理するツールがない場合、またはそのようなツールが利用できない環境でコードが機能することを確認したい場合は、小さなスクリプトが必要です。

#!/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いいえ、SolarisはGNUを使用しませんfind。回答を編集して、GNU以外のソリューションを含めました。
ショーンJ.ゴフ

OK。テキストファイルに貼り付けて実行権限を与えるだけですか?
ランクロ

12

上記には多くの複雑な答えがありますが、これはそれらのすべてよりも簡単で速いようです:

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

サブディレクトリで重複するファイル名を検索する場合は、パス全体ではなくファイル名のみを比較する必要があります。

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

編集:ショーンJ.ゴフは、改行文字を含むファイル名があると失敗することを指摘しました。GNUユーティリティを使用している場合は、これらも機能させることができます。

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

-print0(検索用)及び-z(ソートとuniqのための)オプションそれらの原因NULで終了する文字列の代わりに、改行文字で終了する文字列での作業に。ファイル名にはNULを含めることができないため、これはすべてのファイル名に対して機能します。


1
しかし、Shawn J. Goffの回答に関する私のコメントを参照してください。findに-print0オプションを追加し、uniqおよびsortに-zオプションを追加できます。また、-f on sortも必要です。その後、動作します。(これを回答に編集します。承認しない場合は元に戻してください)
-derobert

最後のコマンドは、キャリッジリターンなしの出力を提供しています(結果はすべて1行で表示されます)。Red Hat Linuxを使用してコマンドを実行しています。最初のコマンドラインが最適です。

2

大文字と小文字を区別しない方法でファイル名のリストをソートし、重複を印刷します。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

1

GNUなしfind

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


2
tr文字ごとに1バイト以上を使用する文字セットで大混乱を引き起こす可能性が非常に高いです。を使用する場合、UTF-8の最初の256文字のみが安全trです。ウィキペディアからtr(Unix) .. GNU およびクラシックUnix を含むほとんどのバージョンはtr、SINGLEtrtr
BYTES

1
以前のコメントを更新します。UTF-8の最初の128文字のみが安全です。序数範囲0..127を超えるUTF-8文字 はすべてマルチバイトであり、他の文字に個々のバイト値を含めることができます。範囲0..127のバイトのみが 、一意の文字と1対1で関連付けられています。
Peter.O

Plusにuniqは、大文字と小文字を区別しないフラグiがあります。
ジェイミーキットソン

1

最終的にこの方法で管理しました。

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

find代わりにlsフルパス(多くのサブディレクトリ)が必要だったので使用しました。私はこれを行う方法を見つけられませんでしたls


2
との両方にsortuniqそれぞれ大文字と小文字を区別しないフラグfとiがあります。
ジェイミーキットソン

-1

その後、ファイルの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.