node_modules
我正在编写一个快速工具来检查 node.js文件夹或 python的内容virtualenv
以获取本机依赖项。作为对此的快速初步近似,我编写了以下命令。
find . | xargs file | awk '/C source/ {print $1} /ELF/ {print $1}'
我可以接受误报,但不能接受误报(例如,文件字面上包含字符串ELF
或C source
可以标记为可疑。),但此脚本也可能会在长文件名(因为xargs
会拆分它们)和包含空格的文件名上中断(因为 awk将按空格分割)和包含换行符的文件名(因为 find 使用换行符来分隔路径)。
find
有没有一种方法可以通过查看 的输出file {}
(可能使用一些附加选项从 的输出中完全删除路径file
)是否与特定的正则表达式匹配来过滤生成的路径?
答案1
达到开悟的关键因素find
;)是:
find
的业务是评估表达式——而不是定位文件。是的,find
当然可以找到文件;但这实际上只是一个副作用。
对于这个问题还有另一种值得了解的方法(也如 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循环find
。find
相反,可以使用运算符 直接对每个文件运行需要执行的操作-exec
,或者嵌入一个 shellfor
循环之内一个find
命令并这样做。
一些额外的原因:
答案2
最简单的方法是为每个文件执行一个小脚本,检查 的简短模式输出file
,如果 的输出file
匹配ELF
或C source
,则打印路径,路径作为 传入$0
。
find . -type f -exec sh -c \
'file -b "$0" | grep -q "^ELF\|^C source" && printf %s\\n "$0"' {} \;
该方案较原方案具有以下优点
-type f
立即过滤掉目录,而不是依赖于输出file
传入参数 as{}
可以避免与文件名中的空格或换行符相关的问题。