2

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

1  2 3
4  5 6
7 88 9

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

1 3 2
4 6 5
7 9 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
4

3 回答 3

1

使用 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
于 2013-08-30T13:42:20.173 回答
1

这是一个快速、肮脏且可改进的解决方案:(已编辑,因为 OP 澄清了数字是浮点数)。

$ 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

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

于 2013-08-29T16:32:28.897 回答
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
    }
}

现在这是应该为您工作的脚本:

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

我在transpose.awk这里使用了两次。一次将行转置为列,然后我将按最后一列进行数字排序,然后再次将行转置为列。它可能不是最有效的解决方案,但它可以根据 OP 的要求工作。

转置 awk 脚本来自:@ghostdog74 来自在 Bash 中转置文件的有效方法

于 2013-08-29T16:10:53.057 回答