Bash 如何使用awk按列的最后一个值对列进行排序?

Bash 如何使用awk按列的最后一个值对列进行排序?,bash,sorting,awk,Bash,Sorting,Awk,我有一个这样的文件(有数百行和数百列) 我想根据最后一行值(或特定行值)对列重新排序 如何使用awk(或其他)完成此任务? 提前感谢您的帮助 编辑:我要感谢所有人,如果我不够清楚,我要道歉。 我想做的是: 以一行为例(例如最后一行) 使用所选行的排序值对矩阵列重新排序,以重新确定顺序 因此,最后一行是7 88 9,排序为7 9 88,然后三列必须重新排序,以便在这种情况下,最后两列交换 四列更一般的示例,再次基于最后一行: 输入: 1 2 3 4 4 5 6 7 7 88.

我有一个这样的文件(有数百行和数百列)

我想根据最后一行值(或特定行值)对列重新排序

如何使用awk(或其他)完成此任务? 提前感谢您的帮助

编辑:我要感谢所有人,如果我不够清楚,我要道歉。 我想做的是:

  • 以一行为例(例如最后一行)
  • 使用所选行的排序值对矩阵列重新排序,以重新确定顺序
因此,最后一行是
7 88 9
,排序为
7 9 88
,然后三列必须重新排序,以便在这种情况下,最后两列交换


四列更一般的示例,再次基于最后一行:

输入:

1    2 3  4
4    5 6  7
7 88.0 9 -3
输出:

 4 1 3 2
 7 4 6 5
-3 7 9 88.0
更新: 创建一个名为
transpose.awk
的文件,如下所示:

{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str OFS a[i,j];
        }
        print str
    }
}
我在这里使用了两次
transpose.awk
。一旦要将行转换为列,我将按最后一列进行数字排序,然后再次将行转换为列。这可能不是最有效的解决方案,但它符合OP的要求


转置awk脚本:来自

的@ghostdog74这里有一个快速、肮脏且可改进的解决方案:(编辑原因是OP澄清了数字是浮点)

要了解那里发生了什么(或至少是其中的一部分):


要使其适用于任意行,请将
tail-n1
替换为
tail-n+$L | head-n1

使用GNU awk的数组排序功能可以优雅地解决此问题。GNU awk允许您使用
PROCINFO
控制数组遍历。因此,需要对文件进行两次传递,第一次传递将最后一条记录拆分为一个数组,第二次传递以值顺序循环数组的索引,并基于索引输出字段。下面的代码可能比我解释得更好

awk 'BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"};
    NR == FNR {for (x in arr) delete arr[x]; split($0, arr)};
    NR != FNR{sep=""; for (x in arr) {printf sep""$x; sep=" "} print ""}' file.txt file.txt
4 1 3 2
7 4 6 5
-3 7 9 88.0


您的意思是在进行相同的列交换之前对最后一行和所有行进行排序吗?为什么前两行被交换,它们不再按任何方向的排序顺序!?我完全不知道这个问题是关于什么的。有人知道了吗?@EdMorton我相信他想切换列的顺序,使最后一行按升序排列。@EdMorton我的理解是,他想对最后一行中的字段进行排序,在排序过程中,字段将被交换。(所谓的重新排序),在最后一行排序之后,他希望上面的所有行都做同样的(重新排序)。我不确定OP真正想要的是切换最后两个值。我有一个这样的文件(有数百行和数百列)@Kent:我真的不理解你的评论。(虽然我可能也误解了OP的要求:P)@Kent:老实说,我无法从最初的问题中看出这一点。如果您注意到时间戳OP在我的答案发布后对排序的说明。@JonathanLeffler:Perl实际上只是一个“改进”的shell,具有改进的缺点。您的代码适用于示例,但奇怪的是,它不适用于我的大矩阵(100列和27000行)。这可能是由于格式?所有的数字都是浮点数,比如'0.018344-0.001763 0'等等@leonardvertighel:你没有提到这些数字是浮点数<代码>排序-n不适用于浮点数。尝试使用
sort-k2g
而不是
sort-k2n
@rici不幸的是,sort-k2g不会产生更改
export LANG=en_US.UTF-8
!!!!愚蠢的语言环境,用逗号分隔小数。感谢所有人的耐心感谢您的优雅解决方案。最后一条记录是否为$0?那么我可以把任何列放在那里吗?@leonardvertighel,你具体想做什么?使用自定义行(在本例中是最后一行,但它可以是任何行或某些行的中间值)作为参考来重新排列矩阵的列。@leonardvertighel,使用第30行,从重新排序的文件中,您可以将上面脚本中的
NR==FNR
更改为
NR==FNR&&NR==30
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str OFS a[i,j];
        }
        print str
    }
}
awk -f transpose.awk file | sort -n -k $(awk 'NR==1{print NF}' file) | awk -f transpose.awk
1 3 2
4 6 5
7 9 88
$ cat test.dat
1 2 3
4 5 6
.07 .88 -.09
$ awk "{print $(printf '$%d%.0s\n' \
                  $(i=0; for x in $(tail -n1 test.dat); do
                           echo $((++i)) $x
                         done |
                  sort -k2g) | paste -sd,)}" test.dat
3 1 2
6 4 5
-.09 .07 .88
$ echo "{print $(printf '$%d%.0s\n' \
                      $(i=0; for x in $(tail -n1 test.dat); do
                               echo $((++i)) $x
                             done |
                      sort -k2g) | paste -sd,)}" test.dat
{print $3,$1,$2} test.dat
awk 'BEGIN{PROCINFO["sorted_in"] = "@val_num_asc"};
    NR == FNR {for (x in arr) delete arr[x]; split($0, arr)};
    NR != FNR{sep=""; for (x in arr) {printf sep""$x; sep=" "} print ""}' file.txt file.txt
4 1 3 2
7 4 6 5
-3 7 9 88.0