使用locate 和find 计算源文件和LOC 时 - 为什么Python 文件出现不同?

使用locate 和find 计算源文件和LOC 时 - 为什么Python 文件出现不同?

我无法理解为什么,find并且locate对于 C 和 Python 源文件的工作方式会有所不同。我的目标是计算给定语言的源文件数量及其源代码行的总和。我使用 和findlocate比较输出(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含义相同(假设不包含斜杠或通配符),但其他模式则不然。例如相当于,而不是。locatefind -nameSUFFIXlocate foofind / -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/scripttemplate(dev).py。现在,错误消息的原因wc应该很清楚了。

对此有几种解决方案。一种是对find和使用空分隔格式xargs。这适用于任何文件名,甚至包含换行符的文件名(这是允许的,但不常见)。

find / -name '*.py' -print0 | xargs -0 wc -l | tail -3

另一种方法是忘记有问题的xargsfind直接调用命令。

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,您只能看到最后两个文件以及最后一批的总数(假设最后一批中至少有两个文件)。先前批次中的文件不会反映在此输出中。由于findlocate可能不会以相同的顺序报告文件,因此您可能会看到不同的结果。

如何解决最大长度问题取决于您想对数据做什么。如果您想要的只是总计,那么一种方法(假设文件名中没有换行符)是计算所有total行。

… | xargs -d '\n' wc -l | awk '/^[0-9]+\ttotal$/ {total += $1} END {print total}'

相关内容