HFS +ファイルシステムから大量のファイルを転送しています。
このファイルは現在ext2パーティションにあります。
ターゲットパーティション(HFS +)が大文字と小文字を区別しないため、競合が発生します。
重複したファイル名を持つ小文字のファイルを識別し、実際に重複している場合は削除したいと思います。
また、すべてを小文字に変換すると、フォルダ名が重複するという事実も発見しました。デフォルトでは、これらのハードドライブには長年ソートされていないデータが含まれており、フォルダ名にも問題があります。
これは合理的に見えますか?
find . -type f | while read f; do echo $f:l; done | sort | uniq -d
$f:l
小文字に変換するのはZSHです。
今、重複した各ファイルのインスタンスを1つだけ維持したいと思います。これを効果的に行う方法は?
重複したファイルを探したくありません。コンテンツ、同じ小文字のファイル名がない限り。後で重複した内容を扱います。
答え1
パイプラインの2番目のステップはわずかに損傷し(バックスラッシュと先行スペースと末尾のスペースを分離)、複雑なアプローチです。tr
小文字に変換するために使用されます。検索をファイルに制限しないでください。ディレクトリでも競合が発生する可能性があります。
find . | tr '[:upper:]' '[:lower:]' | LC_ALL=C sort | LC_ALL=C uniq -d
これは、ファイル名に改行文字が含まれていない場合にのみ機能します。 Linuxでは、改行を処理するための区切り文字でNULLバイトに切り替えます。
find . -print0 | tr '[:upper:]' '[:lower:]' | LC_ALL=C sort -z | LC_ALL=C uniq -dz
これはファイル名の小文字のバージョンを印刷しますが、これは実際にファイルに対して特定の操作を実行するのに役立ちません。
zshを使用している場合は忘れてくださいfind
。必要なものはすべてzshに組み込まれています。
setopt extended_glob
for x in **/*; do
conflicts=($x:h/(#i)$x:t)
if (($#conflicts > 1)); then
## Are all the files identical regular files?
h=()
for c in $conflicts; do
if [[ -f $c ]]; then
h+=(${$(md5sum <$c)%% *})
else
h=(not regular)
break
fi
done
if (( ${#${(@u)h}} == 1 )); then
# Identical regular files, keep only one
rm -- ${conflicts[1,-2]}
else
echo >&2 "Conflicting files:"
printf >&2 ' %s\n' $conflicts
fi
fi
done
答え2
重複したファイル名に対してのみ awk を使用してソリューションを開発しているため、内容を比較しません。
これはawkファイルですdups.awk
#!/usr/bin/awk -f
{
lc=tolower($0);
count[lc] = count[lc]+1;
tab[lc] = tab[lc] "*" $0;}
END {for (t in tab)
if (count[t]>1) {
split(tab[t],sp,"*");
r=1;sep="# ";
for (fn in sp)
if (length(sp[fn]))
{
print sep "rm '" sp[fn] "'";
if (r==1) {r=0; sep=" ";}
}
print ""; }
}
私はそれをそう呼ぶ:
#!/bin/zsh
find $1 -type f | dups.awk
1つの欠陥があります。アスタリスクのあるファイル名では機能しません。
ここで対策を講じてください。
ks% md5sum test/*
e342e6ab6ae71954a772409f23390fa4 test/file1
e342e6ab6ae71954a772409f23390fa4 test/File1
e342e6ab6ae71954a772409f23390fa4 test/file2
ks% ./dupsAwk.sh test
# rm "test/File1"
rm "test/file1"
答え3
File::Find
シェルの複雑さを解決する代わりに、Perlを使用するソリューションは次のとおりです。
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
use Digest::MD5 qw(md5); # To find duplicates
my %lower_case_files_found;
find(
sub{
-f or return; # Skip non-files
push @{$lower_case_files_found{+lc}},$File::Find::name;
},
'.'
);
for my $lower_case_name (sort keys %lower_case_files_found){
my $number_of_files = scalar @{$lower_case_files_found{$lower_case_name}};
if($number_of_files > 1){
my %digests_seen;
for my $file (@{$lower_case_files_found{$lower_case_name}}){
open my $fh,'<',$file or die "Failed to open $file: $!\n";
my $file_content = do {local $/;<$fh>};
my $digest = md5($file_content);
push @{$digests_seen{$digest}},$file;
}
for my $digest (sort keys %digests_seen){
my $num_of_files = scalar @{$digests_seen{$digest}};
if ($num_of_files > 1){
print "Duplicates: \n";
print "[$_]\n" for @{$digests_seen{$digest}}
}
}
}
}
これはMD5合計を使用して重複ファイルを識別し、見つかった重複ファイルのリストを印刷します。各ファイル名は、[]
改行を含むファイル名を視覚的に確認するのに役立つように含まれています。意図的にファイルを削除するコードを追加していません。このコードは完全にテストされていません。。結果リストで何をするかを決定するのはあなたの役割です。
ファイルが大きいと、メモリとCPU使用率が高くなります。上記のスクリプトは各ファイルをメモリにロードし、内容全体に対してMD5の合計を実行します。
答え4
find . -type f |sort |tee f1 |uniq -i |comm -3 - f1
削除または無視するファイルのリストを提供し、それらをパイプでリンクできます。無視リスト再同期の場合
24時間後:
「これは実用的ではありません。別の発見が必要です」というコメントに答えて、結果を名前変更ダメージを与える可能性があるものにリンクするだけです。たとえば、ソリューション全体は単一のコマンドラインにありますが、読みにくいです。
find . -type f |sort |tee f1 |uniq -i |comm -3 - f1|(n=0;while read a ;do n=$((${n}+1));echo mv ${a} `echo ${a}|tr \[:upper:\] \[:lower:\]`_renamed_${n};done)