在unix中对文件的块进行排序

在unix中对文件的块进行排序

我有类似的文件。

HR|testing file
BH|100
B2|cat|10
B2|dog|20
BT|4
BH|105
B2|apple|10
B2|banana|20
B2|melon|10
BT|5
BH|102
B2|fan|10
B2|bulb|20
B2|washer|10
B2|dryer|10
BT|6
TR|17

我需要根据每个块的 BH 记录中的第二个字段对块进行排序。块中的行应保持完整。对于上述文件,预期输出为:

HR|testing file
**BH|100**
B2|cat|10
B2|dog|20
BT|4
**BH|102**
B2|fan|10
B2|bulb|20
B2|washer|10
B2|dryer|10
BT|6
**BH|105**
B2|apple|10
B2|banana|20
B2|melon|10
BT|5
TR|17

答案1

这应该可以工作并根据#BH|#标题行并按升序对BH|100每个BH|102BH|105进行排序...

awk -v RS='BH|TR' 'NR>1{ seen[NR]=$0; next } { printf $0 }
   END{ TR="TR"seen[NR]; delete seen[NR]; asort(seen);  
        for(x in seen) printf "BH"seen[x]; printf TR }' infile

HR|testing file
BH|100
B2|cat|10
B2|dog|20
BT|4
BH|102
B2|fan|10
B2|bulb|20
B2|washer|10
B2|dryer|10
BT|6
BH|105
B2|apple|10
B2|banana|20
B2|melon|10
BT|5
TR|17

  • 这将和RS='BH|TR'定义为记录分隔符(默认为ewline)。BHTR\n

  • 该块NR>1{ seen[NR]=$0; next }将为所有人运行记录但首先(NR数量记录);因此,对于每个记录号作为关联数组的键(索引),称为见过整个记录的值将被设置为它,然后读取next记录。

  • 如果不是第一个记录,那么{ printf $0 }它。这只会运行一次,因为下一次NR>1.

最后该块END{ ... }将运行并执行以下操作:

  • TR="TR"seen[NR]将从数组中复制最后一条记录插入到名为的变量中TR然后将其从数组中删除delete seen[NR]
  • asort(seen)对数组进行排序见过基于他们保存的值;然后
  • 我们循环for(x in seen)这个数组并printf "BH"seen[x]
  • 最后我们打印复制的TR

如果您不介意文件中的第一行和最后一行,您也可以这样做:

sed '1d; $d' infile |awk '{printf $0(/^BT/?"\n":"#")}' |sort |tr '#' '\n'

答案2

我找到了一种快速而简单的方法来做到这一点。请建议是否有更好的方法。

删除了标头和标尾记录。合并并在块中的行之间放入 # 作为行分隔符,将其合并为一行。按特定字段排序用新行替换#

gawk '/^HC/ && line {print line; line=""} {line = line ? line"#"$0 : $0} END {print line}' input.txt | sort -t"|" -nk 13 | tr '#' '\n' > finaloutput.txt

相关内容