从查找中排除文件列表

如果我有一个文本文件中的文件名列表,我想排除当我运行 find,我如何做到这一点?例如,我想做这样的事情:

find /dir -name "*.gz" -exclude_from skip_files

然后把所有的。目录中的 gz 文件,但跳过 _ files 中列出的文件除外。但是 find 没有 -exclude_from标志。如何跳过 skip_files中的所有文件?

90965 次浏览

我觉得你可以试试

find /dir \( -name "*.gz" ! -name skip_file1 ! -name skip_file2 ...so on \)

我不认为 find有这样的选项,您可以使用 printf和排除列表构建一个命令:

find /dir -name "*.gz" $(printf "! -name %s " $(cat skip_files))

这和做事是一样的:

find /dir -name "*.gz" ! -name first_skip ! -name second_skip .... etc

或者你也可以从 find通过管道进入 grep:

find /dir -name "*.gz" | grep -vFf skip_files
find /var/www/test/ -type f \( -iname "*.*" ! -iname  "*.php" ! -iname "*.jpg" ! -iname "*.png"  \)

上面的命令给出所有文件的列表,不包括。菲律宾。Jpg ang.Png 扩展。这个命令对我很管用。

这是我通常从结果中删除一些文件的方法(在这个例子中,我查找了所有的文本文件,但是对于我们这里和那里的一大堆 valGraduate memcheck 报告并不感兴趣) :

find . -type f -name '*.txt' ! -name '*mem*.txt'

好像起作用了。

Josh Jolly 的 grep 解决方案可以工作,但是具有 O (N * * 2)复杂性,因此对于长列表来说太慢了。如果首先对列表进行排序(O (N * log (N))复杂度) ,那么可以使用具有 O (N)复杂度的 comm:

find /dir -name '*.gz' |sort >everything_sorted
sort skip_files >skip_files_sorted
comm -23 everything_sorted skip_files_sorted | xargs . . . etc

详细信息请参阅计算机的 comm

这个解决方案将遍历所有文件(不完全排除 find命令) ,但是将从排除列表中生成一个输出跳过文件。 我发现在运行一个耗时的命令(file /dir -exec md5sum {} \;)时这很有用。

  1. 您可以创建一个 shell 脚本来处理跳跃逻辑并对找到的文件运行命令(使用 chmod使其可执行,用其他命令替换 echo) :
    $ cat skip_file.sh
#!/bin/bash
found=$(grep "^$1$" files_to_skip.txt)
if [ -z "$found" ]; then
# run your command
echo $1
fi
  1. 创建一个文件,其中包含要跳过的名为 files_to_skip.txt的文件列表(在正在运行的目录中)。

  2. 然后使用 find:

    find /dir -name "*.gz" -exec ./skip_file.sh {} \;

这个答案是从 概括另一个答案。您不必列出每个文件名——假设您可以找到定义要排除的一组文件的通用模式或正则表达式。

语法是这样的-括号 ()必须转义:

Find/some/path (myregex) ... 无论如何

例如,考虑一个包含大量文件的文件夹,这些文件的名称反映了创建这些文件的进程或守护进程的名称; 例如,temperature-records-furnaceA-20220729.gz:

$ find . \( -iname "furnaceA" \)

进一步假设我们还想包含 furnaceA的文件,排除2019年和2020年的所有文件:

find . \( -iname "furnaceA" -not "2019" -not "2020" \)

任何可以编写正则表达式的东西都是可能的,至少在 GNU find中,表达式可以使用由 -and-or表达式构造的 组合逻辑进行求值。

这应该会奏效:

find * -name "*.gz" $(printf "! -path %s " $(<skip_files.txt))

健身

  • 假设 skip_files在每一行上都有一个文件名,您可以通过 $(<skip_files.txt)获得文件名列表。例如 echo $(<skip_files.txt)应该把它们都打印出来。
  • 对于每个文件名,都需要一个 ! -path filename表达式
  • 然后,把它与 -name "*.gz"上的过滤器放在一起