首页 > 解决方案 > gawk 和 PROCINFO 在对较长长度的字符串进行排序时无法按预期工作

问题描述

假设我有一个简单的小字符串文件,我想按行长排序:

$ cat file1
123
2
45
12345
123456789
1

我可以编写一个gawk脚本,使用一个函数对这些字符串进行排序,并且PROCINFO["sorted_in"]

$ gawk 'function cmp_len(i1, v1, i2, v2) {
            return length(v1) - length(v2)
      }
      NR==FNR{arr[$0]; next}
      END{PROCINFO["sorted_in"] = "cmp_len"
      for (e in arr) print e
      } 
      ' file1
1
2
45
123
12345
123456789

完美的!

但是现在假设我在该文件中添加了一些更长的字符串:

$ cat file2
123
2
45
xyxyxyxyxyyxyxyxyxyxyyxyxyxxyxyxyxyyxyxyxyxyyx
12345
56565656565656565665656566565656656565656
123456789
1

它打破了:

$ gawk 'function cmp_len(i1, v1, i2, v2) {
            return length(v1) - length(v2)
      }
      NR==FNR{arr[$0]; next}
      END{PROCINFO["sorted_in"] = "cmp_len"
      for (e in arr) print e
      } 
      ' file2
123456789
56565656565656565665656566565656656565656
1
2
45
123
12345
xyxyxyxyxyyxyxyxyxyxyyxyxyxxyxyxyxyyxyxyxyxyyx

它确实以这种方式正常工作:

$ awk '{ print length()"\t"$0}' file2 | sort -n | cut -f2
# expected output by length...

但这使我正在编写的脚本更加困难。

任何想法为什么PROCINFO在这个例子中不使用更长的字符串?

标签: sortingawk

解决方案


手册

这里,“i1”和“i2”是索引,“v1”和“v2”是被比较的两个元素的对应值。

您的比较函数是比较数组的,而不是索引。并且值始终是空字符串,因此函数始终返回 0。将其更改为

function cmp_len(i1, v1, i2, v2) {
         return length(i1) - length(i2)
}            

你会得到你想要的订单。或者更好的是,缓存长度并使用内置比较,因为存储了一个有意义的值:

gawk '
NR==FNR { arr[$0] = length($0) }
END {
        PROCINFO["sorted_in"] = "@val_num_asc"
        for (e in arr) print e
} 
' file1

推荐阅读