我有以下文本文件:
$ cat myfile.txt foo,a,10 bar,c,33 foo,b,50 bar,a,9 foo,a,20 bar,b,20
我想要做的是按第二列和第三(数字降序)sorting,最后select每个第二列组的顶部,导致
foo,a,20 foo,b,50 bar,c,33
我坚持这个:
$ sort -t"," -k2 -k3r test.txt foo,a,10 foo,a,20 bar,a,9 bar,b,20 foo,b,50 bar,c,33
什么是正确的方法来做到这一点?
你的sort
命令是关闭的。 -k
实际上需要一系列的字段,所以你的-k2
被解释为“排序从第二个字段到行尾的所有内容”,它完全忽略了-k3
。 你必须明确的范围开始和结束。 你也想按第三个数字排序。
这就是所有这一切:
$ sort -t, -k2,2 -k3,3nr myfile.txt foo,a,20 foo,a,10 bar,a,9 foo,b,50 bar,b,20 bar,c,33
现在,您要根据第二个字段选择每个组的第一行。 尽管sort
有重复数据流的能力,但处理这种复杂的情况还不够智能。 幸运的是,我们有awk:
$ sort -t, -k2,2 -k3,3nr myfile.txt | awk -F, 'x != $2 { print; x = $2 }' foo,a,20 foo,b,50 bar,c,33
这是纯粹的awk
方法来做到这一点,
awk -F, '{split(a[$2],b,",");if(b[3]<$3)a[$2]=$0}END{for(i in a)print [i]}' myfile.txt
简要说明,
split(a[$2],b,",")
:分隔由','分隔的每个记录,并将每个字段保存到数组b。 if(b[3]<$3)a[$2]=$0
:比较b [3]和$ 3以确定是否需要更新[$ 2] awk smauk
纯粹的BASH!
regex=',(.+),' var="xx" for line in $(sort -t, -k2,2 -k3,3nr myfile.txt); do if [[ $line =~ $regex ]]; then bashrematch=${BASH_REMATCH[1]} if [[ "$var" != "$bashrematch" ]]; then var=$bashrematch echo $line fi fi done foo,a,20 foo,b,50 bar,c,33
只是为了压缩和缩小代码
r=',(.+),'; v=""; for l in $(sort -t, -k2,2 -k3,3nr myfile.txt); do [[ $l =~ $r ]] && b=${BASH_REMATCH[1]} && [ "$v" != "$b" ] && v=$b && echo $l; done foo,a,20 foo,b,50 bar,c,33