查找所有类似名称文件的脚本(仅区分大小写?)

Posted

技术标签:

【中文标题】查找所有类似名称文件的脚本(仅区分大小写?)【英文标题】:Script to find all similarly named files (differing only by case?) 【发布时间】:2011-06-20 17:07:31 【问题描述】:

我一直在仅使用命令行处理 SVN 存储库。我现在必须引入需要 GUI 来与 repo 交互的用户,但是这给类似名称的文件带来了许多问题。

由于缺乏沟通或懒惰,大量图像被复制。

我希望能够从给定文件夹中递归搜索所有文件,并识别所有仅大小写不同的文件,并且必须具有相同的文件大小,因为不同文件之间肯定存在冲突,虽然我还没有遇到过。

我不介意自己编写一个 Perl 脚本来处理这个问题,但是我想知道这样的事情是否已经存在,或者在我卷起袖子之前是否有人有任何提示?

谢谢:D

【问题讨论】:

解决方案应该报告不同文件夹中的重复项,还是只报告同一文件夹中的重复项。例如。 /bert/me.gif 不会被视为与/ernie/me.gif 重复(假设文件大小相同)? 【参考方案1】:

对于此类问题,我依靠 md5sum

find * -type f | xargs md5sum | sort | uniq -Dw32

如果您使用的是 svn,则需要排除 .svn 目录。这将打印出具有相同内容的路径的所有文件。

如果您真的只想匹配大小写不同的文件,您可以在上述管道中添加更多内容:

find * -type f  | xargs md5sum | sort | uniq -Dw32 | awk -F'[ /]' ' print $NF ' | sort -f | uniq -Di
myimage_23.png
MyImage_23.png

【讨论】:

这将显示重复的文件,但不限于名称不同的集合。 对。我正在回答这个问题,对实际问题做出一些假设。我认为 OP 遇到的问题是多个图像或资源已提交给 repo,他们需要整合这些图像或资源。这种方法非常适合。 如果你同意这样的假设,那么 OP 可能更喜欢puzzle-diff 我只希望删除同一目录中大小写不同的文件,以便删除不区分大小写处理文件的系统上的 SVN 错误。不过非常感谢您向我介绍uniq 命令,其中有一个不区分大小写的开关-i :)【参考方案2】:

列出 Subversion 工作目录中所有文件名的 shell 脚本,这些文件名仅在大小写上与同一目录中的另一个文件名不同,因此会导致 Subversion 客户端在不区分大小写的文件系统上出现问题,这些文件名无法区分这些文件名:

寻找 。 -name .svn -type d -prune -false -o -print | \ perl -ne '推@$flc($_), $_; ENDmapprint @$f$_ grep @$f$_>1 排序键 %f'

【讨论】:

【参考方案3】:

我没有亲自使用过,但Duplicate Files Finder 看起来很合适。

但是,无论文件名如何,它都会识别任何重复文件,因此如果您只希望文件名不区分大小写的重复项,则可能必须过滤结果。

它是开源的,可在 Windows 和 Linux 上使用,具有命令行和 GUI 界面,从描述中该算法听起来非常快(仅比较大小相同的文件,而不是为每个文件生成校验和)。

【讨论】:

【参考方案4】:

我猜应该是这样的:

#!perl
use File::Spec;
sub check_dir 
    my ($dir, $out) = @_;
    $out ||= [];
    opendir DIR, $dir or die "Impossible to read dir: $!";
    my @files = sort grep  /^[^\.]/  readdir(DIR); # Ignore files starting with dot
    closedir DIR;
    my @nd = map  ! -d $_ ? File::Spec->catfile($dir, $_) : ()  @files;
    for my $i (0 .. $#nd-1)
        push @$out, $nd[$i]
            if lc $nd[$i] eq lc $nd[$i+1]
            and -s $nd[$i] == -s $nd[$i+1];
    
    map  -d $_ ? &check_dir($_, $out) : ()  @files;
    return $out;

print join "\n", @&check_dir(shift @ARGV), "";

使用前请检查,我无法访问windows机器(这在Un*x中不会发生)。另外,请注意,如果两个文件名称相同(大小写除外)且大小相同,则仅打印第一个文件。在三个的情况下,只有前两个,依此类推(当然,你需要保留一个!)。

【讨论】:

这里没有 Windows 机器,只有 Linux 和 OSX。但是,无论出于何种原因,OSX(版本)上的 SVN 客户端在检出类似命名的文件时遇到问题。【参考方案5】:

据我所知,您想要的并不存在。但是,这是 bash 中的一个实现:

#!/bin/bash

dir=("$@")
matched=()
files=()

lc() tr '[:upper:]' '[:lower:]' <<< $* ; 

in_list() 
    local search="$1"
    shift
    local list=("$@")
    for file in "$list[@]" ; do
        [[ $file == $search ]] && return 0
    done
    return 1



while read -r file ; do
    files=("$files[@]" "$file")
done < <(find "$dir[@]" -type f | sort)


for file1 in "$files[@]" ; do
    for file2 in "$files[@]" ; do
            if
                    # check that the file did not match already
                    ! in_list "$file1" "$matched[@]" &&

                    # check that the files are not the same file
                    ! [ $(stat -f %i "$file1") -eq $(stat -f %i "$file2") ] &&

                    # check that the size of the files are the same
                    [ $(stat -f %z "$file1") = $(stat -f %z "$file2") ] &&

                    # check that the non-directory part (aka file name) of the two
                    # files match case insensitively
                    grep -q $(lc "$file1##*/") <<<$(lc "$file2##*/")
            then
                    matched=("$matched[@]" "$file1")
                    echo "$file1"
                    break
            fi
    done
done

编辑:添加 cmets 并受 TLP 评论的启发,仅将文件部分作为路径的一部分进行相等比较。现在已经在合理的最低程度上进行了测试,我希望它不会在你的脸上爆炸。

【讨论】:

【参考方案6】:

我建议尝试fdupes 或duff

【讨论】:

【参考方案7】:

这是一个 Ruby 脚本,用于递归搜索仅大小写不同的文件。

#!/usr/bin/ruby
# encoding: utf-8

def search( directory )

    set = 
    Dir.entries( directory ).each do |entry|
        next if entry == '.' || entry == '..'
        path = File.join( directory, entry )

        key = path.upcase
        set[ key ] = [] unless set.has_key?( key )
        set[ key ] << entry

        search( path ) if File.directory?( path )
    end

    set.delete_if  |key, entries| entries.size == 1 
    set.each do |key, entries|
        entries.each do |entry|
            puts File.join( directory, entry )
        end
    end

end

search( File.expand_path( ARGV[ 0 ] ) )

【讨论】:

以上是关于查找所有类似名称文件的脚本(仅区分大小写?)的主要内容,如果未能解决你的问题,请参考以下文章

可以使 PHP 的 glob() 以不区分大小写的方式查找文件吗?

在bash脚本中查找包含所有关键字的行

如何使我的本地服务器区分大小写?

查找命令find

shell脚本之正则表达式

飞鱼相册笔记----外置SD卡文件夹名称不区分大小写