AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 468966
Accepted
phg
phg
Asked: 2018-09-14 23:26:39 +0800 CST2018-09-14 23:26:39 +0800 CST 2018-09-14 23:26:39 +0800 CST

计算宽度超过 80 列的行,正确考虑制表符

  • 772

要计算超过 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工具,而不需要预处理文件。

grep
  • 4 4 个回答
  • 1339 Views

4 个回答

  • Voted
  1. Kusalananda
    2018-09-14T23:50:39+08:002018-09-14T23:50:39+08:00

    通过管道对文件进行预处理expand。该expand实用程序将适当地扩展制表符(使用标准制表位在每 8 个字符处停止)。

    find . -type f \( -name '*.[ch]' -o -name '*.p[ly]' \) -exec expand {} + |
    awk 'length > 80 { n++ } END { print n }'
    
    • 12
  2. Stéphane Chazelas
    2018-09-14T23:48:25+08:002018-09-14T23:48:25+08:00

    GNUwc -L不会将 TAB 视为 8 个字符,它会将 TAB 视为它们将显示在终端中,TAB 每 8 列停止一次,因此“宽度”范围为 1 到 8 个字符,具体取决于它们在行上的位置. wc -L还考虑其他字符的显示宽度(无论它们是 0、1 还是 2 列宽),并且还可以\f“\r正确”处理。

    $ printf 'abcde\t\n' | wc -L
    8
    

    在这里,您可以使用expand(默认情况下还假定制表位每 8 列停止,尽管您可以使用选项更改它)将这些制表符扩展为空格:

    git grep -h '' ./**/*.{c,h,p{l,y}} | expand | tr '\f\r' '\n\n' | grep -cE '.{81}'
    

    (将 CR(当发送到终端时将光标移回行首)和 FF(某些显示设备将其理解为分页符)转换为 LF 以获得与 相同的行为wc -L,但忽略其他行为无论如何我们无法判断它们会对显示宽度产生什么影响)。

    这包括制表符,但不包括单角或双角字符。请注意,expand如果存在多字节字符(更不用说零宽度或双宽度字符),当前的 GNU 实现不会正确扩展 TAB。

    $ printf 'ééééé\t\n' | wc -L
    8
    $ printf 'ééééé\t\n' | expand | wc -L
    11
    

    另请注意,./**/*.{c,h,p{l,y}}默认情况下会跳过隐藏文件或隐藏目录中的文件。随着大括号扩展扩展到几个 glob,如果其中任何一个 glob 不匹配,您也会收到错误(致命的zshor )。bash -O failglob

    使用zsh,您将使用./**/*.(c|h|p[ly])(D.)which 是一个glob,其中 whereD包括隐藏文件并.限制为常规文件。

    对于考虑到字符实际宽度的解决方案(假设所有文本文件都以区域设置的字符编码进行编码),您可以使用:

    git grep -h '' ./**/*.(c|h|p[ly])(.) | tr '\r\f' '\n\n' |
      perl -Mopen=locale -MText::Tabs -MText::CharWidth=mbswidth -lne '
        $n++ if mbswidth(expand($_)) > 80;
        END{print 0+$n}'
    

    请注意,至少在 GNU 系统上,mbswidth()将控制字符视为具有宽度-1和 1 的expand(). 我们假设在文件中找不到除 CR、NL、TAB、FF 以外的控制字符。

    • 10
  3. Best Answer
    roaima
    2018-09-15T01:17:07+08:002018-09-15T01:17:07+08:00

    如果我们可以根据您的评论假设制表符只会出现在行首,那么我们可以计算至少 80 个字符的替代品。

    • 没有制表符,至少 81 个字符
    • 一个制表符,至少 73 个字符
    • 两个选项卡,至少 65 个字符
    • 等等。

    结果混乱如下,您的awk语句将各个行数相加以提供总计

    git grep -hcP '^(.{81,}|\t.{73,}|\t{2}.{65,}|\t{3}.{57,}|\t{4}.{49,}|\t{5}.{41,}|\t{6}.{33,}|\t{7}.{25,}|\t{8}.{17,}|\t{9}.{9,}|\t{10}.)' **/*.{c,h,p{l,y}} |
        awk '{ i+=$1 } END { printf ("%d\n", i) }'
    
    • 8
  4. user232326
    2018-09-16T06:23:20+08:002018-09-16T06:23:20+08:00

    ex的解决方案(来自vi)。虽然很慢。

    由于 vi 能够正确处理 UTF-8 数据:

    它可以将制表符扩展到空格,将控制字符计数为 1,\r \t \f \v正确处理并处理大多数有效的UNICODE 值。包括组合 (NKC) 和分解 (NKD) 口音,以及来自西里尔文、阿拉伯文、希腊文、中文和许多其他字符的字符。

    $ cat script.sh
    #!/bin/bash --
    
    declare -i count=0
    
    for i do
        # Set ex script in one variable
        a='set expandtab        "       Expand tabs to spaces
           r '"$i"'             "       Read original file
           g/^.\{,80\}$/d       "       Remove all lines shorter than the value used
           wq                   "       Quit ' 
    
        o=outfile; :>"$o"           # Clean output file
        ex -s "$o" <<<"$a"          # process lines in $i file
        count+=$(wc -l <"$o")       # count and accumulate number of lines.
    done
    
    echo "$count"
    

    调用脚本为:

    $ script.sh     **/*.{c,h,p{l,y}}
    44984
    
    • 1

相关问题

  • 来自 `service | 的意外结果 grep`

  • 读取带有单词的文本文件及其出现次数和排序的打印输出

  • 命令 ls | grep 只显示目录(当它也应该显示文件时)

  • grep 什么时候计数,什么时候不计数

  • grep --line-buffered 直到 X 行?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve