通过解析“file”命令的输出来过滤“find”生成的文件

通过解析“file”命令的输出来过滤“find”生成的文件

node_modules我正在编写一个快速工具来检查 node.js文件夹或 python的内容virtualenv以获取本机依赖项。作为对此的快速初步近似,我编写了以下命令。

find . | xargs file | awk '/C source/ {print $1} /ELF/ {print $1}'

我可以接受误报,但不能接受误报(例如,文件字面上包含字符串ELFC source可以标记为可疑。),但此脚本也可能会在长文件名(因为xargs会拆分它们)和包含空格的文件名上中断(因为 awk将按空格分割)和包含换行符的文件名(因为 find 使用换行符来分隔路径)。

find有没有一种方法可以通过查看 的输出file {}(可能使用一些附加选项从 的输出中完全删除路径file)是否与特定的正则表达式匹配来过滤生成的路径?

答案1

达到开悟的关键因素find;)是:

find的业务是评估表达式——而不是定位文件。是的,find当然可以找到文件;但这实际上只是一个副作用。

--Unix电动工具

对于这个问题还有另一种值得了解的方法(也如 Unix Power Tools 中所述)“使用 -exec 创建自定义测试”):

find . -type f -exec sh -c 'file -b "$1" | grep -iqE "^ELF|^C source"' sh {} \; -print

值得了解这种过滤方法,因为它的用途不仅仅是打印文件名;只需将-print运算符更改为您喜欢的任何其他运算符(包括另一个-exec运算符),然后用它做您喜欢的事情。


那里该命令的性能缺陷(也存在于另一个答案\;),因为我们使用的是and not ,所以+我们为每个文件生成一个 shell。使用+一次将多个文件传递给sh命令并使用for循环处理它们可以带来显着的性能优势:

find . -exec sh -c 'for f do file -b "$f" | grep -qE "^ELF|^C source" && printf %s\\n "$f"; done' sh {} +

您可以通过运行以下两个命令并比较输出来亲自查看比较time

time find . -exec sh -c 'for f do file -b "$f" | grep -qE "^ELF|^C source" && printf %s\\n "$f"; done' sh {} +
time find . -exec sh -c 'file -b "$1" | grep -qE "^ELF|^C source" && printf %s\\n "$1"' sh {} \;

但真正的要点是:

for切勿对从 输出的文件列表运行 shell循环findfind相反,可以使用运算符 直接对每个文件运行需要执行的操作-exec,或者嵌入一个 shellfor循环之内一个find命令并这样做。

一些额外的原因:

答案2

最简单的方法是为每个文件执行一个小脚本,检查 的简短模式输出file,如果 的输出file匹配ELFC source,则打印路径,路径作为 传入$0

find . -type f -exec sh -c \
    'file -b "$0" | grep -q "^ELF\|^C source" && printf %s\\n "$0"' {} \;

该方案较原方案具有以下优点

-type f立即过滤掉目录,而不是依赖于输出file

传入参数 as{}可以避免与文件名中的空格或换行符相关的问题。

相关内容