使用命令行工具计算文件中的行长


72

问题

如果我有一个长文件,其中包含许多行,这些行的长度各不相同,该如何计算每行长度的出现次数?

例:

file.txt

this
is
a
sample
file
with
several
lines
of
varying
length

跑步count_line_lengths file.txt会给:

Length Occurences
1      1
2      2
4      3
5      1
6      2
7      2

有想法吗?


你怎么知道length=1是哪个词?您也应该存储单词。
法案

语言:最好使用一个聪明的shell命令。我可以像Ruby或Python这样轻松地做到这一点,但这并不有趣;)
Pete Hamilton

@Bill我不是很在乎这个词,只是在乎行长,除非我误解了您的问题?
皮特·汉密尔顿

Answers:


103

count.awk:

{
  print length($0);
}

...

$ awk -f count.awk input.txt | sort | uniq -c
      1 1
      2 2
      3 4
      1 5
      2 6
      2 7

85
或更短的时间:awk '{print length}' input.txt | sort | uniq -c
Anders Johansson,

1
不错的烟斗蛇,但计数并uniq可以在里面awk轻松完成。我想排序也可以在中完成gawk。我更喜欢纯bash解决方案。
TrueY

10
我这样做了,但是行长,默认情况下排序没有正确地对数字进行排序(我得到了这样的输出1 9575 1 999。要正确地对数字sort -g进行排序,请使用,使原始awk '{print length}' input.txt | sort -g | uniq -c
user82116

@ user82116我相信用替换该sort命令LC_ALL=C sort也将具有对字符进行正确排序以及更快的优点。
Prometheus

28

纯awk

awk '{++a[length()]} END{for (i in a) print i, a[i]}' file.txt

4 3
5 1
6 2
7 2
1 1
2 2

10

使用bash数组:

#!/bin/bash

while read line; do
    ((histogram[${#line}]++))
done < file.txt

echo "Length Occurrence"
for length in "${!histogram[@]}"; do
    printf "%-6s %s\n" "${length}" "${histogram[$length]}"
done

示例运行:

$ ./t.sh
Length Occurrence
1      1
2      2
4      3
5      1
6      2
7      2

1
@fedorqui但这并不是真正的可移植性,因此取决于用例是否awk胜出;-)刚发布它是因为OP明确要求不涉及另一种外部语言的内容,这也意味着awk(这就是我的阅读方式)。从while read l;do((h[${#l}]++));done<file.txt;for l in "${!h[@]}";do echo "$l ${h[$l]}";done
好的方面来说,

8
$ perl -lne '$c{length($_)}++ }{ print qq($_ $c{$_}) for (keys %c);' file.txt

输出量

6 2
1 1
4 3
7 2
2 2
5 1

2
高尔夫乐趣:perl -lnE '$c{+length}++}{say "$_ $c{$_}" for keys %c'
格伦·杰克曼(Glenn jackman)

3
我有一个文件,文件的行长得很长(700-1000MB),在这里所有的单行文件中,只有这个没有崩溃。+1!
兰德尔·库克

1

您可以仅通过使用基本的unix实用程序来完成此操作:

$ printf“%s%s \ n” $(用于$(cat file.txt)中的行;执行printf $ line | wc -c;完成|排序-n | uniq -c | sed -E“ s /([ 0-9] +)[^ 0-9] +([0-9] +)/ \ 2 \ 1 /“)
1 1
2 2
4 3
5 1
6 2
7 2

这个怎么运作?

  1. 这是源文件:
    $ cat file.txt
    这个
    是
    一种
    样品
    文件
    与
    一些
    线
    的
    变化的
    长度
    
  2. 将源文件的每一行替换为其长度:
    $代表$(cat file.txt )中的行;做printf $ line | wc -c; 完成
    4
    2
    1个
    6
    4
    4
    7
    5
    2
    7
    6
    
  3. 排序并计算出现的次数:
    $用于$(cat file.txt)中的行;做printf $ line | wc -c; 完成| 排序-n | uniq -c
          1 1
          2 2
          3 4
          1 5
          2 6
          2 7
    
  4. 交换并格式化数字:
    $ printf“%s%s \ n” $(用于$(cat file.txt)中的行;执行printf $ line | wc -c;完成|排序-n | uniq -c | sed -E“ s /([ 0-9] +)[^ 0-9] +([0-9] +)/ \ 2 \ 1 /“) 
    1 1
    2 2
    4 3
    5 1
    6 2
    7 2
    

2
wc -c计算字节,而不是字符。如果您使用多字节字符,则会得到较大的数字。试试 echo -n "你好" | wc -cvs. echo -n“你好” | wc -m`。
imrek

@DrunkenMaster您一定是正确的,我应该替换wc -cwc -m吗?
Maksym Ganenko

1
我认为对于任何阅读您的答案的人来说现在都是清楚的,只要参考上面的评论就足够了。
imrek

1

如果您允许交换列并且不需要标题,那么就像

while read line; do echo -n $line | wc -m; done < file | sort | uniq -c

(不带sed或的任何高级技巧awk)将起作用。输出为:

1 1
2 2
3 4
1 5
2 6
2 7

要记住的重要一件事:wc -c计算字节,而不是字符,并且对于包含多字节字符的字符串不会给出正确的长度。因此使用wc -m

参考文献:

优衣库(1)

人排序(1)

男子厕所(1)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.