我有一个这样的文件(有数百行和列)
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
,然后必须以这样的方式对三列进行重新排序,在这种情况下,最后两列是交换的。< / p>
一个四列更通用的例子,再次基于最后一行:
输入:
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
答案 0 :(得分: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 -n1
替换为tail -n+$L|head -n1
答案 1 :(得分: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
答案 2 :(得分: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脚本提供:来自An efficient way to transpose a file in Bash的@ ghostdog74