将多行文本文件排序为一行

将多行文本文件排序为一行

我有一个以下格式的文本文件:

####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY3
VAL31
VAL32
VAL33
VAL34

我想按行对此文件进行排序KEY,并将接下来的 4 行保留在结果中,因此排序结果应该是:

####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY3
VAL31
VAL32
VAL33
VAL34

有没有办法做到这一点 ?

答案1

msort(1)被设计为能够对具有多行记录的文件进行排序。它有一个可选的 GUI,以及一个普通且可供人类使用的命令行版本。 (至少,喜欢仔细阅读手册并寻找示例的人类......)

AFAICT,您不能对记录使用任意模式,因此除非您的记录是固定大小的(以字节为单位,而不是字符或行)。 msort确实有一个-b选项,用于记录由空行分隔的行块。

-b您可以通过在每个输入之前添加一个空行###...(第一个除外) 将输入转换为可以轻松使用的格式。

默认情况下,它在 stderr 上打印统计信息,因此至少很容易判断它何时未排序,因为它认为整个输入是单个记录。


msort适用于您的数据。 该命令在除第 1 行之外的 sed每一行前面添加一个换行符。对整个记录进行排序(按字典顺序)。有一些选项可以选择记录的哪一部分用作密钥,但我不需要它们。#+-w

我还遗漏了去除额外的换行符。

$ sed '2,$ s/^#\+/\n&/' unsorted.records | msort -b -w 2>/dev/null 
####################################
KEY1
VAL11
VAL12
VAL13
VAL14

####################################
KEY2
VAL21
VAL22
VAL23
VAL24

####################################
KEY3
VAL31
VAL32
VAL33
VAL34

我没有任何运气-r '#'使用它作为记录分隔符。它认为整个文件就是一条记录。

答案2

解决方案是首先将块内的换行符更改为您选择的未使用字符(下例中的“|”),对结果进行排序并将所选分隔符更改回原始换行符:

sed -e 'N; N; N; N; N; s/\n/|/g' file.txt \
| sort -k2,2 -t\| \
| sed 's/|/\n/g'

答案3

perl -0ne 'print sort /(#+[^#]*)/g' file.txt
  • perl -0 吞掉整个文件
  • /(....)/g匹配并提取记录
  • print sort ...排序并打印它们

答案4

您可以使用 POSIX awk标准库

#!/usr/local/bin/awklib -f
$0 ~ "#" {x++}
{q[x] = q[x] ? q[x] RS $0 : $0}
END {
  arr_sort(q)
  for (x in q) print q[x]
}

相关内容