我无法理解为什么,find
并且locate
对于 C 和 Python 源文件的工作方式会有所不同。我的目标是计算给定语言的源文件数量及其源代码行的总和。我使用 和find
来locate
比较输出(updatedb
在此之前刚刚运行 和sudo
以确保locate
报告当前结果)。
对于 C 文件,这按预期工作,源文件的数量是相同的
$ find / -name *.c |& grep -v "Permission denied" | wc -l
1056
$ locate *.c | wc -l
1056
使用xargs
,源代码行的总和也相同。
$ locate *.c | xargs wc -l | tail -3
138 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/selinux/genheaders/genheaders.c
147 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/selinux/mdp/mdp.c
705376 total
$ find / -name *.c |& grep -v "Permission denied" | xargs wc -l | tail -3
2994 /opt/Python-3.6.2/Objects/listobject.c
821 /opt/Python-3.6.2/Objects/bytes_methods.c
705376 total
只是为了测试,这也适用于具有.java
扩展名的文件 - 我得到了相同的一致结果。但是,当我对 Python 文件(即.py
扩展名)重复相同的操作时
源文件编号匹配。
$ find / -name *.py |& grep -v "Permission denied" | wc -l
9249
$ locate *.py | wc -l
9249
但是 Python 文件的代码行总和给出了截然不同的结果。
$ locate *.py | xargs wc -l | tail -3
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template: No such file or directory
wc: (dev).py: No such file or directory
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template.py: No such file or directory
220 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/rt-tester/rt-tester.py
129 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/tracing/draw_functrace.py
753350 total
$ find / -name *.py |& grep -v "Permission denied" | xargs wc -l | tail -3
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template: No such file or directory
wc: (dev).py: No such file or directory
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template.py: No such file or directory
1919 /opt/Python-3.6.2/python-gdb.py
69 /opt/Python-3.6.2/python-config.py
1034101 total
有人可以解释为什么会这样吗? Python 文件有什么不同(我真的不敢相信它与文件类型有关,但我很困惑)。我在这里缺少什么?
Ubuntu 和 RH 下同样奇怪的结果
我updatedb
使用运行sudo
,但我以普通用户身份运行所有这些命令。
答案1
你的命令有很多问题。
首先,如果您在不包含任何名称匹配的文件的目录中运行它,则locate *.c
仅查找匹配的文件。否则,shell 将扩展至匹配文件的列表。这可能不会发生,否则你会得到更少的匹配,但是像这样留下不带引号的通配符是一个坏习惯,因为它*.c
*.c
*.c
将要有一天咬你一口。 (这是该网站上的一个常见主题。)这同样适用于find -name *.c
.相反,写
locate '*.c' …
find / -name '*.c' …
或类似的东西。
有一些常见的原因locate
,并且find
可能会产生不同的结果。它们似乎不适用于您的情况,因为您获得的点击次数相同,但您再次需要注意这一点。
locate
缓存上次运行的结果updatedb
。这通常在晚上运行一次。find
每次运行命令时计算的结果。- 根据系统、
locate
您所使用的实现以及它的配置方式,它可能只会让您看到可公开访问的文件(例如 GNU findutils,而不是 mlocate 或 slocate),或者它可能会生成您正在查看的文件的近似值。允许访问(例如,因为有一个涉及 Linux 安全模块的复杂设置,可以区分尝试访问文件的应用程序)。 - 该模式的to和 to
*SUFFIX
含义相同(假设不包含斜杠或通配符),但其他模式则不然。例如相当于,而不是。locate
find -name
SUFFIX
locate foo
find / -name '*foo*'
find / -name 'foo'
另一件可能(但可能不会)导致问题的事情是,您已将错误消息通过管道传输find
到命令的数据处理部分。您删除包含 的行Permission denied
,这会导致您错过包含此作为名称一部分的文件(好吧,您可能没有任何文件),并导致任何不包含的错误消息Permission denied
被解释为输入行。将数据输出与错误输出混合在一起并不是一个好主意,而且在这里这是荒谬的。如果您想忽略错误,请将它们重定向到/dev/null
:
find … 2>/dev/null | …
绝对让你烦恼的是,它所xargs
期望的输入语法与生成的语法不同find
。在 的输入中xargs
,任何空格都会分隔项目,而不仅仅是换行符。这三个字符\'"
也是经过专门解析的。空格在文件名中很常见,除了/
空字节之外,所有其他字符都是允许的。xargs
接收输入的行之一是
/usr/lib/python2.7/site-packages/setuptools/script template (dev).py
对于xargs
,这是三项:/usr/lib/python2.7/site-packages/setuptools/script
、template
和(dev).py
。现在,错误消息的原因wc
应该很清楚了。
对此有几种解决方案。一种是对find
和使用空分隔格式xargs
。这适用于任何文件名,甚至包含换行符的文件名(这是允许的,但不常见)。
find / -name '*.py' -print0 | xargs -0 wc -l | tail -3
另一种方法是忘记有问题的xargs
并find
直接调用命令。
find / -name '*.py' -exec wc -l {} + | tail -3
第一个解决方案可能适用于您的locate
实施,请检查它是否有-0
选项。第二种解决方案特定于find
.如果您坚持使用 的换行符分隔输出locate
,并且您拥有 GNU 版本的xargs
,那么您可以使用-d '\n'
使其将输入解析为换行符分隔,而不需要任何形式的引用。
locate '*.py' | xargs -d '\n' wc -l | tail -3
这是你的主要问题。另一个问题是命令行有最大长度。该xargs
命令(或-exec … {} +
的操作find
)在命令行上放置尽可能多的文件名,如果它们不全部适合,则该命令(此处为wc -l
)会执行多次,每批文件执行一次。使用 时tail -3
,您只能看到最后两个文件以及最后一批的总数(假设最后一批中至少有两个文件)。先前批次中的文件不会反映在此输出中。由于find
和locate
可能不会以相同的顺序报告文件,因此您可能会看到不同的结果。
如何解决最大长度问题取决于您想对数据做什么。如果您想要的只是总计,那么一种方法(假设文件名中没有换行符)是计算所有total
行。
… | xargs -d '\n' wc -l | awk '/^[0-9]+\ttotal$/ {total += $1} END {print total}'