如何按行长度对文件进行排序,然后按第二个关键字的字母顺序进行排序



假设我有一个文件:

ab
aa
c
aaaa

我希望它像这个一样排序

c
aa
ab
aaaa

也就是按行长度排序,然后按字母顺序排序。这在bash中可能吗?

您可以将行的长度预先设置为每行,然后进行数字排序,最后剪切出数字

< your_file awk '{ print length($0), $0; }' | sort -n | cut -f2

您可以看到,我已经通过sort -n完成了排序,而没有进行任何多关键字排序。老实说,我很幸运这起到了作用:

  • 我不认为行可以以数字开头,所以我希望sort -n能工作,因为如果所有字符串的长度都相同,字母和数字排序会给出相同的结果,这是一个例子,因为我们是根据我通过awk添加的行长度排序的。

  • 事实证明,即使你的输入有以数字开头的行,一切都能工作,原因是sort -n

    1. 在行的前导数字部分上对进行数字排序
    2. 关系的情况下,它使用strcmp来比较整条线

    这里有一些演示:

    $ echo -e '3 11n3 2' | sort -n
    3 11
    3 2
    # the `3 ` on both lines makes them equal for numerical sorting
    # but `3 11` comes before `3 2` by `strcmp` before `1` comes before `2`
    $ echo -e '3 11n03 2' | sort -n
    03 2
    3 11
    # the `03 ` vs `3 ` is a numerical tie,
    # but `03 2` comes before `3 11` by `strcmp` because `0` comes before `3`
    

    幸运的是,awk命令中包含的,I插入了一个空格(实际上是OFS(,即一个非数字,因此";断开";数值排序并让strcmp排序生效(在这种情况下,在数值比较相等的整行上(。

    我不知道这种行为是否是POSIX,但我使用的是GNU coreutils 8.32sort。有关详细信息,请参阅我的这个问题和Unix上的这个答案。

awk本身可以完成所有任务,但我认为使用sort进行排序更惯用(如在中,使用sort进行排序(,而且效率更高,正如注释中所解释的那样(毕竟为什么不认为sort是shell中性能最好的排序工具?

使用gawk插入行的长度(零填充到四位,以便正确排序(,按两个键排序(首先是长度,然后是行上的第一个字(,然后删除长度:

gawk '{printf "%04d %sn", length($0), $0}' | sort -k1 -k2 | cut -d' ' -f2-

如果必须是bash:

while read -r line; do printf "%04d %sn" ${#line} "${line}"; done | sort -k1 -k2 | (while read -r len remainder; do echo "${remainder}"; done)

对于GNU awk:

$ gawk '{
a[length()][$0]++                             # hash to 2d array
}
END {
PROCINFO["sorted_in"]="@ind_num_asc"          # first sort on length dim
for(i in a) {
PROCINFO["sorted_in"]="@ind_str_asc"      # and then on data dim
for(j in a[i])
for(k=1;k<=a[i][j];k++)               # in case there are duplicates
print j
# PROCINFO["sorted_in"]="@ind_num_asc"    # I don t think this is needed?
}
}' file

输出:

c
aa
ab
aaaa
aaaaaaaaaa
aaaaaaaaaa

最新更新