ChatGPT解决这个技术问题 Extra ChatGPT

如何递归计算目录中的所有代码行?

我们有一个 PHP 应用程序,想要计算特定目录及其子目录下的所有代码行数。

我们不需要忽略评论,因为我们只是想得到一个粗略的想法。

wc -l *.php 

该命令适用于给定目录,但它忽略子目录。我在想下面的评论可能有效,但它返回 74,这绝对不是这种情况......

find . -name '*.php' | wc -l

以递归方式从目录中输入所有文件的正确语法是什么?


J
Jarl

尝试:

find . -name '*.php' | xargs wc -l

或(当文件名包含空格等特殊字符时)

find . -name '*.php' | sed 's/.*/"&"/' | xargs  wc -l

The SLOCCount tool 也可能有所帮助。

它将为您指向的任何层次结构提供准确的源代码行数,以及一些额外的统计信息。

排序输出:

find . -name '*.php' | xargs wc -l | sort -nr


cloc.sourceforge.net 可能值得作为 sloccount 的替代品(更多语言但信息更少)
还有包含文件:find . -name '*.php' -o -name '*.inc' | xargs wc -l
当有许多文件时,这将打印多个数字(因为 wc 将运行多次。也不处理许多特殊文件名。
@idober:find . -name "*.php" -not -path "./tests*" | xargs wc -l
如果目录名称包含任何空格...上述命令失败!
P
Peter Mortensen

对于另一个单行:

( find ./ -name '*.php' -print0 | xargs -0 cat ) | wc -l

它适用于带有空格的名称,并且只输出一个数字。


+1 同上...永远搜索...所有其他“查找”命令仅返回实际文件的数量......这里的 -print0 内容为我提供了实际的行数!!!谢谢!
我找到的最佳解决方案。我参数化了路径和文件类型,并将此代码添加到我路径上的脚本中。我打算经常使用它。
@TorbenGundtofte-Bruun - 请参阅 man find .. print0 和 xargs -0 让您可以对名称中包含空格或其他奇怪字符的文件进行操作
@TorbenGundtofte-Bruun - 另外,xargs 中的 -0 对应于 print0,它是一种处理空格的编码/解码。
如果您需要多个名称过滤器,我发现(至少使用 MSYSGit 版本的 find),您需要额外的括号:( find . \( -name '*.h' -o -name '*.cpp' \) -print0 | xargs -0 cat ) | wc -l
P
Peter Mortensen

您可以使用专为此目的而构建的 cloc 实用程序。它报告每种语言的行数,以及其中有多少是注释等。CLOC 在 Linux、Mac 和 Windows 上可用。

用法和输出示例:

$ cloc --exclude-lang=DTD,Lua,make,Python .
    2570 text files.
    2200 unique files.
    8654 files ignored.

http://cloc.sourceforge.net v 1.53  T=8.0 s (202.4 files/s, 99198.6 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JavaScript                    1506          77848         212000         366495
CSS                             56           9671          20147          87695
HTML                            51           1409            151           7480
XML                              6           3088           1383           6222
-------------------------------------------------------------------------------
SUM:                          1619          92016         233681         467892
-------------------------------------------------------------------------------

这是一个可爱的工具,运行良好并在最后快速提供有用的统计数据。爱它。
请注意,您可以使用 cygwin(或其他类似的端口/环境)在 Windows 上运行 Unix 命令。对我来说,拥有这种非常有用的访问权限是必要的。 unix 命令行很神奇。我特别喜欢 perl 和正则表达式。
CLOC 和 SLOCCount 在 2015 年中期的 macbook 上运行良好。请注意,对于 127k Java Android 项目,它们的数字很接近,但并不完全相同。另请注意,iOS 等价物具有 2 倍的 LoC;因此,SLOCCount 中的“成本”指标可能会关闭(或者 iOS 开发人员的收入可能是 Android 开发人员的 2 倍。:-)
您是否考虑编辑此问题的开头以明确 cloc 是跨平台的,因为它只是一个 Perl 脚本?
非常完美,当然在 Windows bash 中也能正常工作。
M
Michael Wild

如果使用最新版本的 Bash(或 ZSH),则要简单得多:

wc -l **/*.php

在 Bash shell 中,这需要设置 globstar 选项,否则 ** 全局运算符不是递归的。要启用此设置,请发出

shopt -s globstar

要使其永久化,请将其添加到初始化文件之一(~/.bashrc~/.bash_profile 等)。


为了简单起见,我赞成这一点,但是我只想指出它似乎没有递归搜索目录,它只检查当前目录的子目录。这是在 SL6.3 上。
这取决于您的外壳和您设置的选项。 Bash 需要 globstar to be set 才能工作。
@PeterSenna,使用当前的 3.9.8 内核存档,命令 wc -l **/*.[ch] 总共找到 15195373 行。不确定您是否认为这是“非常低的价值”。同样,您需要确保在 Bash 中启用了 globstar。您可以使用 shopt globstar 检查。要显式启用它,请执行 shopt -s globstar
@MichaelWild 这是一个很好的解决方案,但是如果您有大量 .php 文件,它仍然会溢出 ARG_MAX,因为 wc 不是内置的。
@AlbertSamuel 不,您需要比较两种方法生成的文件列表。正如@BroSlow 所提到的,我的方法存在不适用于大量文件的问题。如果 find 生成的路径包含空格,则接受的答案将失败。这可以通过分别对 findxargs 调用使用 print0--null 来解决。
P
Peter Mortensen

在类 Unix 系统上,有一个名为 cloc 的工具可提供代码统计信息。

我在我们的代码库中运行了一个随机目录,它说:

      59 text files.
      56 unique files.
       5 files ignored.

http://cloc.sourceforge.net v 1.53  T=0.5 s (108.0 files/s, 50180.0 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C                               36           3060           1431          16359
C/C++ Header                    16            689            393           3032
make                             1             17              9             54
Teamcenter def                   1             10              0             36
-------------------------------------------------------------------------------
SUM:                            54           3776           1833          19481
-------------------------------------------------------------------------------

@moose 在技术上 simtao 专门提到它作为 Windows 用户的解决方案,根本没有提到 linux 或 unix。
@moose Table 比我的答案晚得多地编辑到他的答案中,现在两者看起来确实相似。
我喜欢。 cloc真的很整洁。但是这个名字是什么意思?
它现在也在 Windows 上!假设您有 chocolateychoco install cloc
P
Peter Mortensen

您没有指定有多少文件或所需的输出是什么。

这可能是您正在寻找的:

find . -name '*.php' | xargs wc -l

只要文件不多,这将起作用:如果文件很多,您将得到几行结果(xargs 会将文件列表拆分为几个子列表)
是的。这就是为什么我说他没有具体说明有多少文件。我的版本更容易记住,但如果你有多个文件,Shin 的版本会更好。我投票赞成。
我需要调整它以用于单引号过于严格的函数:go () { mkdir /tmp/go; [[ -f ./"$1" ]] && mv ./"$1" /tmp/go; (find ./ -type f -name "$*" -print0 | xargs -0 cat ) | wc -l; wc -l /tmp/go/*; mv /tmp/go/* . } 结果接近 *.py 的 slocount,但它不知道 *.js*.html
P
Peter Mortensen

还有另一种变化:)

$ find . -name '*.php' | xargs cat | wc -l

这将给出总和,而不是逐个文件。

find 之后添加 . 以使其工作。


至少在 cygwin 中,我有更好的结果:$ find -name \*\.php -print0 | xargs -0 cat | wc -l
在达尔文,这只是给出一个总数:find . -name '*.php' | xargs cat | wc -l ...而这给出了一个文件一个文件和一个总数:find . -name '*.php' | xargs wc -l
P
Peter Mortensen

使用 find-execawk。开始了:

find . -type f -exec wc -l {} \; | awk '{ SUM += $0} END { print SUM }'

此代码段查找所有文件 (-type f)。要按文件扩展名查找,请使用 -name

find . -name '*.py' -exec wc -l '{}' \; | awk '{ SUM += $0; } END { print SUM; }'

从功能上讲,这工作得很好,但在大型列表(linux 源代码)上它真的很慢,因为它为每个文件启动一个 wc 进程,而不是为所有文件启动一个 wc 进程。我使用此方法将其计时为 31 秒,而使用 find . -name '*.c' -print0 |xargs -0 wc -l 时为 1.5 秒。也就是说,这种更快的方法(至少在 OS X 上)最终会打印“总计”多次,因此需要进行一些额外的过滤才能获得正确的总计(我在答案中发布了详细信息)。
这样做的好处是可以处理无限数量的文件。做得好!
一旦处理大量 GB 和文件,这是更好的解决方案。在 cat 的形式上执行一个 wc 很慢,因为系统首先必须处理所有 GB 才能开始计算行数(使用 200GB 的 jsons、12k 文件进行测试)。先做wc然后计算结果要快得多
@DougRichardson,您可以考虑改为: find . -type f -exec wc -l {} \+find . -name '*.py' -type f -exec wc -l {} \+ 在输出末尾打印总计。如果您只对总数感兴趣,那么您可以更进一步并使用 tailfind . -type f -exec wc -l {} \+ | tail -1find . -name '*.py' -type f -exec wc -l {} \+ | tail -1
P
Peter Mortensen

对我来说更常见和更简单,假设您需要计算不同扩展名的文件(比如,也是本地人):

wc $(find . -type f | egrep "\.(h|c|cpp|php|cc)" )

这并不完全符合您的想法。寻找 。 -name '.[am]' 与 find 相同。 -name '.[a|m]' 都将查找所有以 .m 或 .a 结尾的文件
但第二个也会找到以 .| 结尾的文件,如果有的话。所以 [h|c|cpp|php|cc] 最终与 [hcp|] 相同。
反引号已弃用,更喜欢 $()
这在 Cygwin 下有效。当然,“C:\”驱动器必须遵循 cygwin 约定,例如: wc $(find /cygdrive/c//SomeWindowsFolderj/ -type f | egrep "\.(h|c|cpp|php|抄送)”)
P
Paul Draper

POSIX

与此处的大多数其他答案不同,这些答案适用于任何 POSIX 系统,适用于任意数量的文件和任何文件名(除非另有说明)。

每个文件中的行:

find . -name '*.php' -type f -exec wc -l {} \;
# faster, but includes total at end if there are multiple files
find . -name '*.php' -type f -exec wc -l {} +

每个文件中的行,按文件路径排序

find . -name '*.php' -type f | sort | xargs -L1 wc -l
# for files with spaces or newlines, use the non-standard sort -z
find . -name '*.php' -type f -print0 | sort -z | xargs -0 -L1 wc -l

每个文件中的行数,按行数降序排列

find . -name '*.php' -type f -exec wc -l {} \; | sort -nr
# faster, but includes total at end if there are multiple files
find . -name '*.php' -type f -exec wc -l {} + | sort -nr

所有文件的总行数

find . -name '*.php' -type f -exec cat {} + | wc -l

P
Peter Mortensen

工具 Tokei 显示有关目录中代码的统计信息。 Tokei 将显示文件数、这些文件中的总行数以及按语言分组的代码、注释和空白。 Tokei 也可在 Mac、Linux 和 Windows 上使用。

Tokei 的输出示例如下:

$ tokei
-------------------------------------------------------------------------------
 Language            Files        Lines         Code     Comments       Blanks
-------------------------------------------------------------------------------
 CSS                     2           12           12            0            0
 JavaScript              1          435          404            0           31
 JSON                    3          178          178            0            0
 Markdown                1            9            9            0            0
 Rust                   10          408          259           84           65
 TOML                    3           69           41           17           11
 YAML                    1           30           25            0            5
-------------------------------------------------------------------------------
 Total                  21         1141          928          101          112
-------------------------------------------------------------------------------

可以按照 the instructions on the README file in the repository 安装 Tokei。


很棒的工具,谢谢。
J
John Bachir

有一个名为 sloccount 的小工具可以计算目录中的代码行数。

应该注意的是,它所做的比您想要的要多,因为它忽略了空行/注释,按编程语言对结果进行分组并计算一些统计数据。


对于 Windows,LocMetrics 完成这项工作
重复接受的答案(尽管同时发布)。
P
Peter Mortensen

您需要一个简单的 for 循环:

total_count=0
for file in $(find . -name *.php -print)
do
    count=$(wc -l $file)
    let total_count+=count
done
echo "$total_count"

与建议 xargs 的答案相比,这不是矫枉过正吗?
不,内森。 xargs 答案不一定会将计数打印为单个数字。它可能只打印一堆小计。
如果文件名包含空格,这个程序会做什么?换行符呢? ;-)
如果您的文件名包含新行,我会说您有更大的问题。
@ennukiller 这个问题的数量,首先它会在带有空格的文件上中断。在循环之前设置 IFS=$'\n' 至少可以为除名称中带有换行符的文件之外的所有文件修复它。其次,你没有引用 '*.php',所以它会被 shell 而不是 find 扩展,因此实际上不会在子目录中找到任何 php 文件。 -print 也是多余的,因为它隐含在没有其他操作的情况下。
P
Peter Mortensen

仅适用于来源:

wc `find`

要过滤,只需使用 grep

wc `find | grep .php$`

P
Peter Mortensen

一个简单的快速的,将使用 find 的所有搜索/过滤功能,当文件太多时不会失败(数字参数溢出),可以很好地处理名称中带有有趣符号的文件,而不使用 {2 },并且不会启动大量无用的外部命令(感谢 find-exec+)。干得好:

find . -name '*.php' -type f -exec cat -- {} + | wc -l

我正要自己发布一个变体(使用 \; 而不是 +,因为我不知道),这个答案应该是正确的答案。
我做了( find . -type f -exec cat {} \; |wc -l )然后我看到了这个。只是想知道这个解决方案中的“--”和“+”是什么意思,以及与我的版本在外部命令数量方面的区别。
@grenix:您的版本将为找到的每个文件生成一个新的 cat,而 \+ 版本将在一次调用中将找到的所有文件提供给 cat-- 用于标记选项的结束(这里有点不必要)。
我不明白这是如何避免参数数量溢出的。如果我确实'找到 . -type f -exec cat -- {} + |more' 和 ' ps aux|grep "cat "' 在另一个终端我得到类似 '... 66128 0.0 0.0 7940 2020 pts/10 S+ 13:45 0:00猫——./file1 ./file2 ...'
J
Ja͢ck

我知道该问题被标记为 ,但您尝试解决的问题似乎也与 PHP 相关。

Sebastian Bergmann 编写了一个名为 PHPLOC 的工具,可以满足您的需求,并在此基础上为您提供项目复杂性的概览。这是其报告的一个示例:

Size
  Lines of Code (LOC)                            29047
  Comment Lines of Code (CLOC)                   14022 (48.27%)
  Non-Comment Lines of Code (NCLOC)              15025 (51.73%)
  Logical Lines of Code (LLOC)                    3484 (11.99%)
    Classes                                       3314 (95.12%)
      Average Class Length                          29
      Average Method Length                          4
    Functions                                      153 (4.39%)
      Average Function Length                        1
    Not in classes or functions                     17 (0.49%)

Complexity
  Cyclomatic Complexity / LLOC                    0.51
  Cyclomatic Complexity / Number of Methods       3.37

如您所见,从开发人员的角度来看,提供的信息要有用得多,因为它可以在您开始使用项目之前大致告诉您项目的复杂程度。


P
Peter Mortensen

到目前为止,没有一个答案涉及带空格的文件名问题。

此外,如果树中路径的总长度超过 shell 环境大小限制(Linux 中默认为几兆字节),则所有使用 xargs 的操作都会失败。

这是一个以非常直接的方式解决这些问题的方法。子shell 负责处理带有空格的文件。 awk 总计单个文件 wc 输出的流,因此它永远不会耗尽空间。它还将 exec 限制为仅文件(跳过目录):

find . -type f -name '*.php' -exec bash -c 'wc -l "$0"' {} \; | awk '{s+=$1} END {print s}'

真的,这是一个诚实的问题。能够在比让其他人在 SO 上为您做这件事所需的时间更短的时间内自己做这种事情绝对是一个渴望成为软件工程师的人应该具备的技能。我不是屈尊俯就。如果你自己弄清楚这一点,你就会领先。
a
alexis

如果您想保持简单,请去掉中间人,只需使用所有文件名调用 wc

wc -l `find . -name "*.php"`

或者在现代语法中:

wc -l $(find . -name "*.php")

只要在任何目录名或文件名中没有空格,它就可以工作。并且只要您没有数以万计的文件(现代 shell 支持非常长的命令行)。您的项目有 74 个文件,因此您有足够的增长空间。


我喜欢这个!如果您处于混合 C/C++ 环境中:wc -l `find . -type f \( -name "*.cpp" -o -name "*.c" -o -name "*.h" \) -print`
P
Peter Mortensen

WC-L ?更好地使用 GREP -C ^

wc -l错了!

wc 命令计算新行代码,not 行!当文件的最后一行没有以换行码结束时,不计算在内!

如果您仍然想要计算行数,请使用 grep -c ^。完整示例:

# This example prints line count for all found files
total=0
find /path -type f -name "*.php" | while read FILE; do
     # You see, use 'grep' instead of 'wc'! for properly counting
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count #in bash, you can convert this for another shell
done
echo TOTAL LINES COUNTED:  $total

最后,注意 wc -l 陷阱(计数输入,而不是行!!!)


请阅读POSIX definition of a line。使用 grep -c ^ 您计算的是 incomplete lines 的数量,这样不完整的行不能出现在 text file 中。
我知道。实际上,只有最后一行可能不完整,因为它没有 EOL。想法正在计算所有行,包括不完整的行。这是非常常见的错误,只计算完整的行。数完后,我们在想“为什么我错过了最后一行???”。这就是为什么,以及如何正确地做到这一点的答案。
或者,如果您想要一个衬里:find -type f -name '*.php' -print0 | xargs -0 grep -ch ^ | paste -sd+ - | bc 请参阅此处了解 bc 的替代品:stackoverflow.com/q/926069/2400328
M
Matt

首先给出最长的文件(即,也许这些长文件需要一些重构的爱?),并排除一些供应商目录:

 find . -name '*.php' | xargs wc -l | sort -nr | egrep -v "libs|tmp|tests|vendor" | less

在生成的代码或在构建过程中复制的文件的项目中,排除目录很重要
P
Peter Mortensen

对于 Windows,一个简单快捷的工具是 LocMetrics


如果他们使用 bash,OP 不太可能在 Windows 上。
@VanessaMcHale 问题标题和描述都没有明确要求仅适用于 unix 的解决方案。所以基于 Windows 的解决方案是可以接受的。当我在寻找类似的解决方案时,谷歌也将我指向了这个页面。
这条评论帮助了我。我试过了,效果很好。
P
Peter Mortensen

您可以使用名为 codel (link) 的实用程序。这是一个简单的 Python 模块,可以用彩色格式计算行数。

安装

pip install codel

用法

要计算 C++ 文件的行数(带有 .cpp.h 扩展名),请使用:

codel count -e .cpp .h

您还可以忽略一些 .gitignore 格式的文件/文件夹:

codel count -e .py -i tests/**

它将忽略 tests/ 文件夹中的所有文件。

输出如下所示:

https://i.stack.imgur.com/dNckF.jpg

您还可以使用 -s 标志缩短输出。它将隐藏每个文件的信息并仅显示有关每个扩展名的信息。示例如下:

https://i.stack.imgur.com/ctJED.jpg


有没有办法对所有文本文件执行此操作,而不仅仅是特定的扩展名?
@AaronFranke 现在没有办法了。
P
Paul Pettengill

如果您希望结果按行数排序,只需将 | sort| sort -r-r 用于降序)添加到第一个答案,如下所示:

find . -name '*.php' | xargs wc -l | sort -r

由于 xargs wc -l 的输出是数字,因此实际上需要使用 sort -nsort -nr
P
Peter Mortensen

很简单:

find /path -type f -name "*.php" | while read FILE
do
    count=$(wc -l < $FILE)
    echo "$FILE has $count lines"
done

如果其中一个文件名中有空格或换行符,它将失败
P
Peter Mortensen

有些不同:

wc -l `tree -if --noreport | grep -e'\.php$'`

这很好用,但您需要在当前文件夹或其子文件夹之一中至少有一个 *.php 文件,否则 wc 会停止。


也可能溢出 ARG_MAX
P
Peter Mortensen

使用 Z shell (zsh) glob 非常简单:

wc -l ./**/*.php

如果你使用 Bash,你只需要升级。绝对没有理由使用 Bash。


D
Doug Richardson

至少在 OS X 上,其他一些答案中列出的 find+xarg+wc 命令在大型列表中多次打印“total”,并且没有给出完整的总数。我能够使用以下命令获得 .c 文件的单个总数:

find . -name '*.c' -print0 |xargs -0 wc -l|grep -v total|awk '{ sum += $1; } END { print "SUM: " sum; }'


您可以使用 grep total 而不是 grep -v total - 它将对 wc 给出的中间和求和。重新计算中间和没有意义,因为 wc 已经这样做了。
b
bharath

如果文件太多,最好只查找总行数。

find . -name '*.php' | xargs wc -l | grep -i ' total' | awk '{print $1}'

P
Peter Mortensen

如果您只需要总行数,比方说,您的 PHP 文件,如果您安装了 GnuWin32,即使在 Windows 下也可以使用非常简单的一行命令。像这样:

cat `/gnuwin32/bin/find.exe . -name *.php` | wc -l

您需要指定 find.exe 的确切位置,否则将执行 Windows 提供的 FIND.EXE(来自旧的类似 DOS 的命令),因为它可能在环境 PATH 中的 GnuWin32 之前,并且具有不同的参数和结果。

请注意,在上面的命令中,您应该使用反引号,而不是单引号。


在上面的示例中,我使用 bash for windows 而不是 cmd.exe,这就是为什么有正斜杠“/”而不是反斜杠“\”的原因。
P
Peter Mortensen

虽然我喜欢这些脚本,但我更喜欢这个脚本,因为它还显示每个文件的摘要,只要总数:

wc -l `find . -name "*.php"`

回复“……只要一个总数……”:你的意思不是“……以及一个总数……”吗?