我有一个以下格式的文本文件:
####################################
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]
}