我的文件中有 1 亿行。
每行只有一列。
例如
aaaaa
bb
cc
ddddddd
ee
Run Code Online (Sandbox Code Playgroud)
我想列出字符数
像这样
2 character words - 3
5 character words - 1
7 character words - 1
Run Code Online (Sandbox Code Playgroud)
等等。
有什么简单的方法可以在终端中做到这一点吗?
Kus*_*nda 20
$ awk '{ print length }' file | sort -n | uniq -c | awk '{ printf("%d character words: %d\n", $2, $1) }'
2 character words: 3
5 character words: 1
7 character words: 1
Run Code Online (Sandbox Code Playgroud)
第一个awk
过滤器将只打印名为file
. 我假设这个文件每行包含一个单词。
的sort -n
(来自的输出排序线awk
和数值在升序)uniq -c
(计数次数每一行连续出现的数目),然后将从该给定数据创建的输出如下:
3 2
1 5
1 7
Run Code Online (Sandbox Code Playgroud)
然后由第二个awk
脚本解析,该脚本将每一行解释为“X 个具有 Y 个字符的行”并产生所需的输出。
另一种解决方案是全部完成awk
并将长度计数保存在数组中。这是效率、可读性/易于理解(以及因此可维护性)之间的权衡,哪种解决方案是“最好的”。
替代解决方案:
$ awk '{ len[length]++ } END { for (i in len) printf("%d character words: %d\n", i, len[i]) }' file
2 character words: 3
5 character words: 1
7 character words: 1
Run Code Online (Sandbox Code Playgroud)
Sun*_*eep 10
另一种awk
独自完成这一切的方法
$ awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' ip.txt
2 character words - 3
5 character words - 1
7 character words - 1
Run Code Online (Sandbox Code Playgroud)
words[length()]++
使用输入行的长度作为键来保存计数END{for(k in words)print k " character words - " words[k]}
处理完所有行后,以所需格式打印数组内容
性能比较,选择的数字是两次运行中最好的
$ wc words.txt
71813 71813 655873 words.txt
$ perl -0777 -ne 'print $_ x 1000' words.txt > long_file.txt
$ du -h --apparent-size long_file.txt
626M long_file.txt
$ time awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1
real 0m20.632s
user 0m20.464s
sys 0m0.108s
$ time perl -lne '$h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}' long_file.txt > t2
real 0m19.749s
user 0m19.640s
sys 0m0.108s
$ time awk '{ print length }' long_file.txt | sort -n | uniq -c | awk '{ printf("%d character words - %d\n", $2, $1) }' > t3
real 1m23.294s
user 1m24.952s
sys 0m1.980s
$ diff -s <(sort t1) <(sort t2)
Files /dev/fd/63 and /dev/fd/62 are identical
$ diff -s <(sort t1) <(sort t3)
Files /dev/fd/63 and /dev/fd/62 are identical
Run Code Online (Sandbox Code Playgroud)
如果文件只有 ASCII 字符,
$ time LC_ALL=C awk '{words[length()]++} END{for(k in words)print k " character words - " words[k]}' long_file.txt > t1
real 0m15.651s
user 0m15.496s
sys 0m0.120s
Run Code Online (Sandbox Code Playgroud)
不知道为什么时间perl
没有太大变化,可能编码必须以其他方式设置
这是一个perl
等效的(带有 - 可选 - 排序):
$ perl -lne '
$h{length($_)}++ }{ for $n (sort keys %h) {print "$n character words - $h{$n}"}
' file
2 character words - 3
5 character words - 1
7 character words - 1
Run Code Online (Sandbox Code Playgroud)
另一种调用 GNU awk,使用printf:
$ awk 'BEGIN { PROCINFO["sorted_in"] = "@ind_str_asc"}
{c[length($0)]++}
END{
for(i in c){printf("%s character words - %s\n",i,c[i])}
}' infile
2 character words - 3
5 character words - 1
7 character words - 1
Run Code Online (Sandbox Code Playgroud)
核心算法只是收集数组中的字符数。最后部分打印收集的计数,格式为 printf。
快速、简单,一次调用 awk。
准确地说:使用更多内存来保存数组。
但是没有调用排序(数字数组索引设置为始终使用 PROCINFO 向上遍历排序),并且只有一个外部程序:awk
,而不是几个。