我对 Linux 还很陌生,我发现了很多关于如何在文件中进行字符计数的有用信息,但是 Linux/terminal 中有没有一种方法可以按特定的次数对文本文件进行排序每行出现一个字符?
例如给出:
baseball
aardvark
a man a plan a canal panama
cat
bat
bill
按字母“a”出现的次数排序,得到:
a man a plan a canal panama
aardvark
baseball
cat
bat
bill
关于“cat”和“bat”各出现一次“a”,我不关心具有相同计数的行的顺序是否颠倒,只对按字符频率进行的一般行排序感兴趣。
答案1
此类任务的一般方法是使用awk
or perl
... 来计算您感兴趣的指标并将其添加到行前面,然后将其提供给已排序的输出sort
并从排序的输出中删除该指标:
awk '{print gsub("a","a"), $0}' < file | sort -rn | cut -d' ' -f2-
答案2
另一个施瓦茨变换:
$ awk -Fa '{print NF,$0}' file | sort -nr | cut -d' ' -f2-
a man a plan a canal panama
aardvark
baseball
cat
bat
bill
或者,在 Perl 中:
perl -Fa -lane 'print "$#F $_"' file | sort -nr | cut -d' ' -f2-
答案3
您也可以仅根据字符进行排序:
tr -cd a\\n <file | paste - ./file | LC_ALL=C sort -rk1,1 | cut -f2-
这是您的示例在通过管道输入之前经过tr
anslated 和d 之后的样子:paste
sort
aa baseball
aaa aardvark
aaaaaaaaaa a man a plan a canal panama
a cat
a bat
bill
然后sort
获取它,并且在所有条件相同的情况下,将较短的键排序在较长的键之前,但反过来-r
,它的输出是......
aaaaaaaaaa a man a plan a canal panama
aaa aardvark
aa baseball
a cat
a bat
bill
...然后cut
只删除第一个选项卡。
a man a plan a canal panama
aardvark
baseball
cat
bat
bill
答案4
由于已经提到了 Schwartzian 变换,我很惊讶地发现还没有人发布其纯 Perl 实现:
perl -ne 'push @a, $_ }{ print map { $_->[0] } sort { $b->[1] <=> $a->[1] } map { [$_, $_ =~ tr/a//] } @a' file
a man a plan a canal panama
aardvark
baseball
cat
bat
bill
文件的每一行都被推送到@a
,然后一旦读取文件,a
就使用字符计数对数组进行排序。
由于计算字符出现的次数并不是一个计算成本很高的函数,因此更简洁的方法是单独使用排序:
$ perl -ne 'push @a, $_ }{ print sort { $b =~ tr/a// <=> $a =~ tr/a// } @a' file
a man a plan a canal panama
aardvark
baseball
cat
bat
bill