我的文件中有 1 亿行。
每行只有一列。
例如
aaaaa
bb
cc
ddddddd
ee
我想列出字符数
像这样
2 character words - 3
5 character words - 1
7 character words - 1
ETC。
有没有简单的方法可以在终端中执行此操作?
答案1
$ 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
第一个awk
过滤器将仅打印名为 的文件中每行的长度file
。我假设该文件每行包含一个单词。
(按升序sort -n
对输出中的行进行数字排序)和(计算每行连续出现的次数)将为给定数据创建以下输出:awk
uniq -c
3 2
1 5
1 7
然后由第二个awk
脚本对其进行解析,该脚本将每一行解释为“具有 Y 个字符的 X 行”并生成所需的输出。
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
答案2
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
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
如果文件只有 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
不知道为什么时间perl
没有改变太多,可能编码必须以其他方式设置
答案3
这是一个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
答案4
替代一调用 GNU awk,使用打印函数:
$ 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
核心算法只是收集数组中的字符计数。结尾部分打印用 printf 格式化的收集的计数。
快速、简单,一次调用 awk。
准确地说:更多的内存用于保存数组。
但没有调用任何排序(数字数组索引设置为始终使用 PROCINFO 向上遍历排序),并且只有一个外部程序:awk
,而不是多个。