我有一个包含 4n 行的文件。这是其中包含 8 行的摘录
6115 8.88443
6116 6.61875
6118 16.5949
6117 19.4129
6116 6.619
6117 16.5979
6118 19.4111
6115 8.88433
我想要做的是对一个块进行排序,其中每个块由基于第一列的 4 行组成。摘录的输出应如下所示。
6115 8.88443
6116 6.61875
6117 19.4129
6118 16.5949
6115 8.88433
6116 6.619
6117 16.5979
6118 19.4111
答案1
一种选择是使用awk每 N 行添加一个初始序列号前缀(在您的情况下 N=4)。然后将前缀作为主要排序列输入到 中sort
。
N=4 的示例:
awk '{print int((NR-1)/4), $0}' file.txt | sort -n -k1,1 -k2,2 | cut -f2- -d' '
答案2
如果这是一次性的,并且您不想学习 python、perl 或 awk,您可以学习 basicsplit
和sort
命令。
首先使用以下选项将文件分成 4 行块-l
:
split -a 6 -l 4 input_file my_prefix_
for fn in my_prefix_*; do
sort -n -o $fn $fn
done
cat my_prefix_* > output_file
rm my_prefix_*
sort -n
按第一列的数值排序(1234 之前的 999) 。-a 6
应该处理 26^6*4 行的文件。my_prefix_
应该是您使用的目录所特有的内容。
答案3
你可以用 Perl 来做到这一点:
perl -nle '
push @a,$_;
unless($. % 4){
print join "\n",sort {$a <=> $b} @a; # Sort @a, and print its contents
@a = (); # Empty @a to start a new block
}
' your_file
这是如何运作的
-n
--> 为每个输入行运行代码(并将当前行放入$_
)-l
--> 将换行符附加到任何的输出print
-e
--> 将以下字符串作为 Perl 代码执行- 每一行都附加到数组中
@a
。 $.
保存当前行号,除非该行号不等于 0 模 4,否则我们将继续工作。如果它是与 0 模 4 同余,我们到达了一行,其编号是 4 的倍数(块的末尾),在这种情况下,我们按@a
升序对条目进行排序,并打印由 a 连接的排序数组中的条目换行符到标准输出。
答案4
以下是一些“纯粹”的awk
解决方案:
如果索引始终是相同的递增整数序列 (6115-6119),如示例数据中所示,则可以使用算法“快捷方式”:
awk '{a[$1]=$0} !(NR%4){for(i=6115;i<6119;print a[i++]);}'
这确实
- 将所有行添加到数组中
a
,分布在索引位置 6115-6119 - 在每 4 行 (
!(NR%4)
) 上,循环遍历数组内容以按所需顺序打印。
如果您的数字索引始终是四个相同的索引,但不是递增的整数序列,则必须进行排序:
awk '{a[$1]=$0} !(NR%4){asort(a,b); for(i=1;i<5;print b[i++]);}'
注意:这是 GNU awk 的,其他人可能不支持asort
。
如果每个四块可以有不同的数字 ID:
awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;print a[i++]); delete a}'
注:TIL来自@Gilles self-answer(+2) 这种用法delete
还不是 POSIX,但得到普遍支持。
正确™使用的版本delete
:
awk '{a[$1]=$0} !(NR%4){asort(a); for(i=1;i<5;delete a[i++]){print a[i]}}'
没有删除的版本,使用更多内存和维度:
awk '{a[n][$1]=$0} !(NR%4){asort(a[n]); for(i=1;i<5;print a[n][i++]); n++}