关于linux:如何计算代码行,包括子目录

How to count lines of code including sub-directories

本问题已经有最佳答案,请猛点这里访问。

假设我想计算项目中的代码行数。如果所有文件都在同一目录中,我可以执行:

1
cat * | wc -l

但是,如果存在子目录,则不起作用。要使这个工作,cat必须有一个递归模式。我怀疑这可能是Xargs的工作,但我想知道是否有更优雅的解决方案?


首先,您不需要使用cat来计算行数。这是一个名为无用的cat(uuoc)的反模式。要计算当前目录中文件中的行数,请使用wc

1
wc -l *

然后,find命令重复使用子目录:

1
find . -name"*.c" -exec wc -l {} \;
  • .是开始搜索的顶级目录的名称。

  • -name"*.c"是您感兴趣的文件的模式。

  • -exec发出要执行的命令

  • {}是要传递给命令的find命令的结果(此处为wc-l)

  • \;表示命令结束。

此命令将生成一个包含行计数的所有文件的列表,如果要获得找到的所有文件的总和,可以使用find列出文件(使用-print选项),然后使用xargs将此列表作为参数传递给wc-l。

1
find . -name"*.c" -print | xargs wc -l

编辑以解决Robert Gamble评论(谢谢):如果您有空格或换行符!!)在文件名中,必须使用-print0选项而不是-printxargs -null选项,这样文件名列表就可以用以空结尾的字符串交换。

1
find . -name"*.c" -print0 | xargs -0 wc -l

Unix的理念是让工具只做一件事,并且做好它。


如果你想要一个代码高尔夫答案:

1
grep '' -R . | wc -l

单独使用wc-l的问题是它不能很好地下降,而oneliner使用

1
find . -exec wc -l {} \;

不会给出总行数,因为它对每个文件运行一次wc,(lol!)和

1
find . -exec wc -l {} +

一旦find达到参数的~200k1,2个字符的参数限制,就会很困惑,而是多次调用wc,每次只给出部分摘要。

此外,当遇到二进制文件时,上面的grep技巧不会向输出添加超过1行,这可能是一种有益的情况。

对于额外1个命令字符的开销,可以完全忽略二进制文件:

1
 grep '' -IR . | wc -l

如果您还想对二进制文件运行行计数

1
 grep '' -aR . | wc -l

有关限制的脚注:

文档对于它是字符串大小限制还是令牌数量限制有点含糊不清。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cd /usr/include;
find -type f -exec perl -e 'printf qq[%s => %s
], scalar @ARGV, length join q[ ], @ARGV'
{} +
# 4066 => 130974
# 3399 => 130955
# 3155 => 130978
# 2762 => 130991
# 3923 => 130959
# 3642 => 130989
# 4145 => 130993
# 4382 => 130989
# 4406 => 130973
# 4190 => 131000
# 4603 => 130988
# 3060 => 95435

这意味着它会非常容易地分裂。


我想你可能被沙尔茨缠住了

1
find -name '*php' | xargs cat | wc -l

Chromakode的方法给出了相同的结果,但速度慢得多。如果您使用xargs,您的cating和wcing可以在find开始查找时立即开始。

Linux的好解释:xargs与exec


正确的方法是:

1
find . -name"*.c" -print0 | xargs -0 cat | wc -l

必须使用-print0,因为unix文件名中只有两个无效字符:空字节和"/"(斜杠)。例如,"xxxPasswd"是一个有效的名称。但实际上,您更可能遇到名称中带有空格的名称。上面的命令将每个单词作为一个单独的文件进行计数。

您可能还希望使用"-type f"而不是-name来限制对文件的搜索。


尝试使用find命令,该命令在默认情况下重复使用目录:

find . -type f -execdir cat {} \; | wc -l


如果您可以使用相对较新的GNU工具,包括bash,那么在上述解决方案中使用cat或grep是浪费的:

1
wc -l --files0-from=<(find . -name \*.c -print0)

这将使用空格、任意递归和任意数量的匹配文件来处理文件名,即使它们超过了命令行长度限制。


我喜欢在项目目录中的所有文件上使用find和head作为"递归cat",例如:

1
find . -name"*rb" -print0 | xargs -0 head -10000

其优点是head将添加您的文件名和路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
==> ./recipes/default.rb <==
DOWNLOAD_DIR = '/tmp/downloads'
MYSQL_DOWNLOAD_URL = 'http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.10-debian6.0-x86_64.deb'
MYSQL_DOWNLOAD_FILE ="#{DOWNLOAD_DIR}/mysql-5.6.10-debian6.0-x86_64.deb"

package"mysql-server-5.5"
...

==> ./templates/default/my.cnf.erb <==
#
# The MySQL database server configuration file.
#
...

==> ./templates/default/mysql56.sh.erb <==
PATH=/opt/mysql/server-5.6/bin:$PATH

有关这里的完整示例,请参阅我的博客文章:

http://haildata.net/2013/04/using-cat-recursive-with-finally-formatted-output-including-headers/

注意,我使用了"head-10000",很明显,如果文件超过10000行,这将截断输出…不过,我可以使用head 100000,但是对于"非正式项目/目录浏览",这种方法对我来说非常有效。


1
wc -cl `find . -name"*.php" -type f`

如果只想为每个文件生成总行数而不是行数,例如:

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

很好用。这样就省去了在脚本中进行进一步文本过滤的需要。


1
find . -name"*.h" -print | xargs wc -l


下面是一个计算项目中代码行数的bash脚本。它递归地遍历源树,并排除使用"/"的空行和单行注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# $excluded is a regex for paths to exclude from line counting
excluded="spec\|node_modules\|README\|lib\|docs\|csv\|XLS\|json\|png"

countLines(){
  # $total is the total lines of code counted
  total=0
  # -mindepth exclues the current directory (".")
  for file in `find . -mindepth 1 -name"*.*" |grep -v"$excluded"`; do
    # First sed: only count lines of code that are not commented with //
    # Second sed: don't count blank lines
    # $numLines is the lines of code
    numLines=`cat $file | sed '/\/\//d' | sed '/^\s*$/d' | wc -l`
    total=$(($total + $numLines))
    echo" " $numLines $file
  done
  echo" " $total in total
}

echo Source code files:
countLines
echo Unit tests:
cd spec
countLines

以下是我的项目的输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Source code files:
   2 ./buildDocs.sh
   24 ./countLines.sh
   15 ./css/dashboard.css
   53 ./data/un_population/provenance/preprocess.js
   19 ./index.html
   5 ./server/server.js
   2 ./server/startServer.sh
   24 ./SpecRunner.html
   34 ./src/computeLayout.js
   60 ./src/configDiff.js
   18 ./src/dashboardMirror.js
   37 ./src/dashboardScaffold.js
   14 ./src/data.js
   68 ./src/dummyVis.js
   27 ./src/layout.js
   28 ./src/links.js
   5 ./src/main.js
   52 ./src/processActions.js
   86 ./src/timeline.js
   73 ./src/udc.js
   18 ./src/wire.js
   664 in total
Unit tests:
   230 ./ComputeLayoutSpec.js
   134 ./ConfigDiffSpec.js
   134 ./ProcessActionsSpec.js
   84 ./UDCSpec.js
   149 ./WireSpec.js
   731 in total

享受!——Curran