要计算超过 80 列的行数,我目前正在使用以下命令:
$ git grep -h -c -v '^.\{,80\}$' **/*.{c,h,p{l,y}} \
|awk 'BEGIN { i=0 } { i+=$1 } END { printf ("%d\n", i) }'
44984
不幸的是,repo 使用制表符进行缩进,因此grep
模式不准确。无论如何,是否有regex
标准宽度为 8 个字符的处理选项卡,就像如何wc -L
做的那样?
出于这个问题的目的,我们可以假设贡献者有足够的纪律性以一致地缩进,或者他们有git commit
钩子代替纪律。
出于与性能相关的原因,我更喜欢在内部工作的解决方案,
git-grep(1)
或者可能是另一个grep
工具,而不需要预处理文件。
通过管道对文件进行预处理
expand
。该expand
实用程序将适当地扩展制表符(使用标准制表位在每 8 个字符处停止)。GNU
wc -L
不会将 TAB 视为 8 个字符,它会将 TAB 视为它们将显示在终端中,TAB 每 8 列停止一次,因此“宽度”范围为 1 到 8 个字符,具体取决于它们在行上的位置.wc -L
还考虑其他字符的显示宽度(无论它们是 0、1 还是 2 列宽),并且还可以\f
“\r
正确”处理。在这里,您可以使用
expand
(默认情况下还假定制表位每 8 列停止,尽管您可以使用选项更改它)将这些制表符扩展为空格:(将 CR(当发送到终端时将光标移回行首)和 FF(某些显示设备将其理解为分页符)转换为 LF 以获得与 相同的行为
wc -L
,但忽略其他行为无论如何我们无法判断它们会对显示宽度产生什么影响)。这包括制表符,但不包括单角或双角字符。请注意,
expand
如果存在多字节字符(更不用说零宽度或双宽度字符),当前的 GNU 实现不会正确扩展 TAB。另请注意,
./**/*.{c,h,p{l,y}}
默认情况下会跳过隐藏文件或隐藏目录中的文件。随着大括号扩展扩展到几个 glob,如果其中任何一个 glob 不匹配,您也会收到错误(致命的zsh
or )。bash -O failglob
使用
zsh
,您将使用./**/*.(c|h|p[ly])(D.)
which 是一个glob,其中 whereD
包括隐藏文件并.
限制为常规文件。对于考虑到字符实际宽度的解决方案(假设所有文本文件都以区域设置的字符编码进行编码),您可以使用:
请注意,至少在 GNU 系统上,
mbswidth()
将控制字符视为具有宽度-1
和 1 的expand()
. 我们假设在文件中找不到除 CR、NL、TAB、FF 以外的控制字符。如果我们可以根据您的评论假设制表符只会出现在行首,那么我们可以计算至少 80 个字符的替代品。
结果混乱如下,您的
awk
语句将各个行数相加以提供总计ex的解决方案(来自vi)。虽然很慢。
由于 vi 能够正确处理 UTF-8 数据:
它可以将制表符扩展到空格,将控制字符计数为 1,
\r
\t
\f
\v
正确处理并处理大多数有效的UNICODE 值。包括组合 (NKC) 和分解 (NKD) 口音,以及来自西里尔文、阿拉伯文、希腊文、中文和许多其他字符的字符。调用脚本为: