【问题标题】: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 重复(假设文件大小相同)?

标签: perl bash case-sensitive filesize


【解决方案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 '推@{$f{lc($_)}}, $_; END{map{print @{$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】:

        我建议尝试fdupesduff

        【讨论】:

          【解决方案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 ] ) )
          

          【讨论】:

            猜你喜欢
            • 2014-11-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-02-03
            • 2018-01-17
            • 2016-11-24
            • 1970-01-01
            • 2012-06-27
            相关资源
            最近更新 更多