查找与文件名模式列表不匹配的文件

查找与文件名模式列表不匹配的文件

我发现自己需要查找和识别无关文件(在 2T 驱动器上的大约 900K 个文件中)。有很多文件我想保留,并且我有这些已知好文件的文件名模式。我想要的是找到那些不符合任何模式的文件。

如何查找与文件名模式列表不匹配的文件?

我可以运行find来获取所有文件的列表,并且可以grep -v使用存储在文件中的模式列表来使用结果。这是规范的方法,还是您有一种简洁的方法来查找这些不合格的文件?


澄清 - 根据答案,这里有更多信息。我期望有大量模式(>20,也许>100),我想将它们存储在一个文件中,并且当然想要一种简单的方法来添加新模式。我宁愿避免直接编辑大量查找参数(脆弱),但构建该列表可能会起作用。

答案1

find(1)功能强大,足以满足您的需求。只需使用括号将所有符合的名称收集到一个表达式中,然后将其取反即可显示不合格文件名。例如,显示所有文件不是命名为*.txt, *.bz2, 或*.zip:

$ find . \! \( -name \*.txt -o -name \*.bz2 -o -name \*.zip \)

您可以使用GNU 和 BSD 来-not代替。它不符合 POSIX 标准,但不需要转义来阻止 shell 解释它。\!find

要根据文件中的模式构建表达式,只需编写 shell 脚本即可:

#!/bin/sh
set --
while IFS= read -r pattern
do
    set -- "$@" -o "$pattern"
done < .fnpatterns
if [ $# -ne 0 ]; then
  shift
  set -- -not \( "$@" \)
fi
find . "$@"

这需要当前目录中的一个文件,.fnpatterns每行调用一个模式。为了模仿上面的一行,它需要包含:

*.txt
*.bz2
*.zip

请注意,shell 脚本会*为您转义模式中的字符。

您可以将其变得任意复杂。一些想法:

  • 添加-type ffind命令中,使其仅显示普通文件,而不显示目录。

  • 将模式文件名作为参数传递,而不是期望它位于固定位置

  • 将模式文件保留在原来的位置,但添加-o -name .fnpatterns到构建find命令中,这样它就不会显示在输出中。 (这也可以避免黑客shift“吃掉”-o构建表达式中的铅。)

  • find通过或类似方式向命令添加操作-exec

  • 模式文件中允许空行或注释

答案2

既然你提到了 Perl...

#!/usr/bin/perl

use strict;
use warnings;
use File::Find qw{find};

my %patterns;
while (<>) {
  chomp;
  $patterns{$_}++;
}

die "No pattern supplied\n" unless keys %patterns;

find( 
    sub{
           my $matches_a_pattern=0;
           for my $pattern (keys %patterns){
               my $glob_pattern = $pattern;
               for($glob_pattern){
                   s/\./\\./g;
                   s/\*/.*/g;
                   s/\?/./g;
               }
               $matches_a_pattern++ if ( /\Q$pattern\E/ or /$glob_pattern/);
           }

           print "$File::Find::name\n" unless $matches_a_pattern;
     }
    , '.' )

将此调用为

/path/to/my/script file_with_patterns

将末尾的 替换.为您要行走的树顶。

相关内容