Bash 递归计算代码行数,包括压缩(zip)文件

Bash 递归计算代码行数,包括压缩(zip)文件,bash,Bash,我使用以下Bash脚本计算我的一个项目中的代码行数: echo "--- CLIENT" cd "/mypath/client" # Count classes: a=`find . -name \*.java -print | wc -l` echo "" echo "Number of Java classes: $a" # Total count: b=`find . -name \*.java -exec

我使用以下Bash脚本计算我的一个项目中的代码行数:

echo "--- CLIENT"
cd "/mypath/client"

# Count classes:
a=`find . -name \*.java -print | wc -l`
echo ""
echo "Number of Java classes: $a"

# Total count:
b=`find . -name \*.java -exec cat {} \; | wc -l`
echo ""
echo "Java lines: $b"

c=`find . -name \*.css -exec cat {} \; | wc -l`
echo ""
echo "CSS lines: $c"

d=`find . -name \*.json -exec cat {} \; | wc -l`
echo ""
echo "JSON lines: $d"

f=$((`find . -name \*.h -exec cat {} \; | wc -l` + `find . -name \*.m -exec cat {} \; | wc -l`))
echo ""
echo "iOS Objective-C lines: $f"

echo ""
echo "--- SERVER"
cd "/mypath/server"
# Count classes:
h=`find . -name \*.java -print | wc -l`
echo ""
echo "Number of Java classes: $h"

# Total count:
i=`find . -name \*.java -exec cat {} \; | wc -l`
echo ""
echo "Java lines: $i"


echo ""
echo "Total lines of code: $((b + c + d + e + f + i))"

cd ~
只要所有的源代码都可以通过这种方式搜索,这个脚本就可以正常工作。现在,我有了一个不同的用例:一些源代码仍然可以通过这个脚本访问,一些源代码在压缩的zip文件中(位于“/mypath/client”的各个子文件夹中)。这些zip文件可以包含根目录中的源文件,也可以包含其中的各个子文件夹中的源文件

我想可以调整我的脚本以考虑计数中的压缩文件,但我不知道如何进行。

计数文件 搜索
.xyz
文件时,还要搜索
.zip
文件并搜索其文件列表。 您可以使用
zipinfo archive.zip
列出zip存档中的所有文件名
zipinfo
还支持通配符以仅打印匹配的文件名。例如,
zipinfo archive.zip'*.java'
只打印以
.java
结尾的文件名

find . -name \*.java -print \
    -o -name \*.zip -exec zipinfo -1 {} '*.java' \; |
wc -l
此命令假定文件名不包含换行符

计数线 使用
unzip-p archive.zip file1 file2…
可以打印压缩文件,而无需显式解压缩它们。此命令还接受通配符

顺便说一下:您可以通过使用函数大大简化脚本,因为
find-名称\*.xyz-exec cat{}\|wc-l
通常是相同的,除了
xyz
。而且,
-exec cat{}+
-exec cat{}快得多

#! /bin/bash

countLines() {
  local ext=$1
  find . -name "*.$ext" -exec cat {} + \
      -o -name \*.zip -exec unzip -p {} "*.$ext" \; |
  wc -l
}

for ext in java css json; do
  echo "$ext lines: $(countLines "$ext")"    
done
unzip-p archive.zip'*.java'
可能会打印警告
注意:文件名不匹配:*.java
如果没有
.java
文件。您可以通过在
find
命令之后添加
2>/dev/null
来抑制这种情况

请记住,这种方法效率很低<代码>查找
必须为每个文件扩展名运行。zip文件也会被读取多次。首先筛选出所有要检查的文件,然后对所有文件运行
wc-l
,然后汇总它们的行计数,这样会更快。

对文件进行计数 搜索
.xyz
文件时,还要搜索
.zip
文件并搜索其文件列表。 您可以使用
zipinfo archive.zip
列出zip存档中的所有文件名
zipinfo
还支持通配符以仅打印匹配的文件名。例如,
zipinfo archive.zip'*.java'
只打印以
.java
结尾的文件名

find . -name \*.java -print \
    -o -name \*.zip -exec zipinfo -1 {} '*.java' \; |
wc -l
此命令假定文件名不包含换行符

计数线 使用
unzip-p archive.zip file1 file2…
可以打印压缩文件,而无需显式解压缩它们。此命令还接受通配符

顺便说一下:您可以通过使用函数大大简化脚本,因为
find-名称\*.xyz-exec cat{}\|wc-l
通常是相同的,除了
xyz
。而且,
-exec cat{}+
-exec cat{}快得多

#! /bin/bash

countLines() {
  local ext=$1
  find . -name "*.$ext" -exec cat {} + \
      -o -name \*.zip -exec unzip -p {} "*.$ext" \; |
  wc -l
}

for ext in java css json; do
  echo "$ext lines: $(countLines "$ext")"    
done
unzip-p archive.zip'*.java'
可能会打印警告
注意:文件名不匹配:*.java
如果没有
.java
文件。您可以通过在
find
命令之后添加
2>/dev/null
来抑制这种情况


请记住,这种方法效率很低<代码>查找
必须为每个文件扩展名运行。zip文件也会被读取多次。首先筛选出所有要检查的文件,然后对所有文件运行
wc-l
,然后对它们的行数进行汇总,这样会更快。

为了简化,我只要有一个只考虑如何修改行“a=
find.-name\*.java-print | wc-l
”的答案就足够了,其他所有内容都会相应地出现。您可以在脚本中添加特定于zip的部分。类似于
j=`find-name\*.zip-exec unzip-l{}\|grep'\.java$'| wc-l`
。为了简化,我的答案只考虑如何修改行“a=
find.-name\*.java-print | wc-l
”,其他所有内容都会相应出现。您可以在脚本中添加特定于zip的部分。类似于
j=`find-name\*.zip-exec unzip-l{}\|grep'\.java$''wc-l`
。谢谢!在我接受你的答案之前,我需要做一些实验和研究,因为它似乎给了我比我预期更多的数值结果。我对Bash的了解仅限于基本内容,我需要一些时间来理解您所写的内容。我已经彻底、广泛地尝试了您的解决方案。在简单的情况下,它是有效的。在非常复杂的项目中,出现了一些问题,有时报告的数字远远高于实际数字,有时即使没有代码或只有几行代码,也会报告数万行代码。我不知道为什么会发生这种情况,有些地方出了问题,但我不知道是什么。解决方法是:使用中指示的命令将所有内容解压缩到临时文件夹中,并应用问题中指示的相同计算脚本。这样一来,计数是正确的,与我预期的相等。@FrancescoGalgani感谢您的测试。我想我发现了问题所在
unzip-p
接受通配符。是否在有问题的项目中,您的一个压缩源文件的名称包含
*?[]
?如果是这样,可能会导致打印更多的文件。有趣的是,修复使整个程序变得更简单。我接受了你的答案:修复后,即使在复杂的项目上,计算现在也是正确的。谢谢,谢谢!在我接受你的答案之前,我需要做一些实验和研究,因为它似乎给了我比我预期更多的数值结果。我对Bash的了解仅限于基本内容,我需要一些时间来理解您所写的内容。我已经彻底、广泛地尝试了您的解决方案。在简单的情况下,它是有效的。关于非常复p