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

Chu*_*ill 9 bash find perl

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

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

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


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

War*_*ung 23

find(1)足够强大,可以做你需要的。只需使用括号将所有符合条件的名称收集到表达式中,然后将其取反以显示不符合条件的文件名。例如,要显示所有文件没有命名*.txt*.bz2*.zip

$ find . \! \( -name \*.txt -o -name \*.bz2 -o -name \*.zip \)
Run Code Online (Sandbox Code Playgroud)

您可以使用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 . "$@"
Run Code Online (Sandbox Code Playgroud)

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

*.txt
*.bz2
*.zip
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 将模式文件名作为参数传入,而不是将其放在固定位置

  • 将模式文件保留在原处,但添加-o -name .fnpatterns到内置find命令中,使其不会出现在输出中。(这也将避免shift黑客“吃掉”-o内置表达式中的铅的需要。)

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

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


Jos*_* R. 3

既然你提到了 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;
     }
    , '.' )
Run Code Online (Sandbox Code Playgroud)

将此调用为

/path/to/my/script file_with_patterns
Run Code Online (Sandbox Code Playgroud)

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