如何查找具有相同名称但在Linux中同一目录中存在的不同情况下的重复文件?

Cam*_*oft 29 linux filesystems bash command-line find

如何返回名为duplicates的文件列表,即具有相同名称但存在于同一目录中的不同情况?

我不关心文件的内容.我只需要知道任何具有相同名称副本的文件的位置和名称.

示例重复:

/www/images/taxi.jpg
/www/images/Taxi.jpg
Run Code Online (Sandbox Code Playgroud)

理想情况下,我需要从基本目录中递归搜索所有文件.在上面的例子中它是/www/

Chr*_*röm 38

另一个答案是伟大的,但我建议不是"相当可怕"的perl脚本

perl -pe 's!([^/]+)$!lc $1!e'
Run Code Online (Sandbox Code Playgroud)

这将只小写路径的文件名部分.

编辑1:实际上整个问题可以通过以下方式解决:

find . | perl -ne 's!([^/]+)$!lc $1!e; print if 1 == $seen{$_}++'
Run Code Online (Sandbox Code Playgroud)

编辑3:我找到了一个使用sed,sort和uniq的解决方案,它也会打印出重复项,但它只有在文件名中没有空格时才有效:

find . |sed 's,\(.*\)/\(.*\)$,\1/\2\t\1/\L\2,'|sort|uniq -D -f 1|cut -f 1
Run Code Online (Sandbox Code Playgroud)

编辑2:这是一个较长的脚本,将打印出名称,它采用stdin上的路径列表,如下所示find.不是很优雅,但仍然:

#!/usr/bin/perl -w

use strict;
use warnings;

my %dup_series_per_dir;
while (<>) {
    my ($dir, $file) = m!(.*/)?([^/]+?)$!;
    push @{$dup_series_per_dir{$dir||'./'}{lc $file}}, $file;
}

for my $dir (sort keys %dup_series_per_dir) {
    my @all_dup_series_in_dir = grep { @{$_} > 1 } values %{$dup_series_per_dir{$dir}};
    for my $one_dup_series (@all_dup_series_in_dir) {
        print "$dir\{" . join(',', sort @{$one_dup_series}) . "}\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

  • +1.我强烈建议接受*这一个*作为答案(而不是我目前接受的答案).它更优雅.我的最终版本是一个怪物,因为我从管道的角度来看它并且不得不添加perl以解决tr的问题.这个答案证明了你通常可以通过退回并重新开始获得更好的解决方案. (5认同)
  • 如果要将其限制为常规文件(无目录),请使用"find -type f". (2认同)

pax*_*blo 35

尝试:

ls -1 | tr '[A-Z]' '[a-z]' | sort | uniq -c | grep -v " 1 "
Run Code Online (Sandbox Code Playgroud)

简单,真的:-)不是管道美妙的野兽?

ls -1给你的文件,每行一个,在tr '[A-Z]' '[a-z]'将所有大写字母为小写,在sort各种他们(令人惊讶的是),uniq -c删除重复行后续出现的同时给你一个数,以及和,最后,grep -v " 1 "带出这些行,其中计数一.

当我在一个"重复"(我复制qqqQ)的目录中运行它时,我得到:

2 qq
Run Code Online (Sandbox Code Playgroud)

对于"此目录和每个子目录"版本,只需替换ls -1find .或者find DIRNAME如果需要特定的目录起始点(DIRNAME是您要使用的目录名称).

这返回(对我来说):

2 ./.gconf/system/gstreamer/0.10/audio/profiles/mp3
2 ./.gconf/system/gstreamer/0.10/audio/profiles/mp3/%gconf.xml
2 ./.gnome2/accels/blackjack
2 ./qq
Run Code Online (Sandbox Code Playgroud)

这是由:

pax> ls -1d .gnome2/accels/[bB]* .gconf/system/gstreamer/0.10/audio/profiles/[mM]* [qQ]?
.gconf/system/gstreamer/0.10/audio/profiles/mp3
.gconf/system/gstreamer/0.10/audio/profiles/MP3
.gnome2/accels/blackjack
.gnome2/accels/Blackjack
qq
qQ
Run Code Online (Sandbox Code Playgroud)

更新:

实际上,在进一步反思时,tr会将路径的所有组件小写,以便两者兼而有之

/a/b/c
/a/B/c
Run Code Online (Sandbox Code Playgroud)

即使它们位于不同的目录中,也会被认为是重复的.

如果你只希望在一个目录中重复显示为匹配,你可以使用(相当怪异):

perl -ne '
    chomp;
    @flds = split (/\//);
    $lstf = $f[-1];
    $lstf =~ tr/A-Z/a-z/;
    for ($i =0; $i ne $#flds; $i++) {
        print "$f[$i]/";
    };
    print "$x\n";'
Run Code Online (Sandbox Code Playgroud)

取代:

tr '[A-Z]' '[a-z]'
Run Code Online (Sandbox Code Playgroud)

它的作用是仅仅小写路径名的最后部分而不是整个部分.此外,如果您只想要常规文件(没有目录,FIFO等),请使用find -type f限制返回的内容.

  • 很好的答案,但有一个很小的优化建议:如果您重定向到管道,我认为您不需要ls上的"-1". (2认同)

mpe*_*ez0 6

我相信

ls | sort -f | uniq -i -d
Run Code Online (Sandbox Code Playgroud)

更简单,更快速,并将给出相同的结果