一行多行排序文本文件


14

我有一个这种格式的文本文件:

####################################
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

有没有办法做到这一点 ?


5
不要交叉后
赞纳

@Zanna:我认为unix和askubuntu部分是被排除在外的,因为这两个部分彼此之间有很多重叠!我想我在Unix的meta部分中读到了有关此信息
RYN

2
AU mod在这里问到的相关元问题:) 应该如何处理在Ask Ubuntu上交叉发布的问题?
Zanna

@RYN问题不会是重叠的,实际上很多SE网站都重叠了,但是给出答案的人可能不知道其他网站上的答案。
phk

Answers:


13

msort(1)旨在能够对具有多行记录的文件进行排序。它具有可选的gui以及普通的和可用于人类的命令行版本。(至少,喜欢仔细阅读手册并寻找示例的人...)

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

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

默认情况下,它会在stderr上打印统计信息,因此至少可以很容易分辨出何时未排序,因为它认为整个输入都是一条记录。


msort处理您的数据。sed命令在第1行#+以外的每一行前添加 换行符-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 '#'将其用作记录分隔符。它认为整个文件是一个记录。


非常感谢你; msort非常有用;谢谢(大概-r是因为我使用了不止一个#-d它起作用了
RYN

凉!(+1)msort -qwr '#' ex 为我工作(它会
破坏

9

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

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

1
谢谢; 这是可行的,但是特别是当数据也很脏时,它非常脏!如果键之后的行是100,那么我需要在该行中放置100 ;N,那么很难找到文本本身未使用的字符;它对sort或非常awk
有用

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

2

这是应该与节中任意数量的行一起使用的另一种方式KEY

# extract delimiter
delim=$(head -n1 <infile)
sed '/#/d;/KEY/h;G;s/\n/\x02/' infile | nl -ba -nrz -s $'\002' | sort -t $'\002' -k3 -k1,1 |
cut -d $'\002' -f2 | sed '/KEY/{x;s/.*/'"${delim}"'/;G}'

通过将分隔符保存到变量中(然后将其从输入中删除),可以工作。然后KEY*,它使用低ascii字符(在您的输入中不太可能出现)作为分隔符将追加到其相应部分的每一行,然后使用相同的分隔符来n累加所有lines。然后,仅需sort在第三个字段和第一个字段中进行ing cut,然后对中间列进行调整,然后通过final恢复定界符即可sed。请注意,以上内容KEY12会先排序,然后根据您的需要KEY2调整sort命令。


2

您可以使用POSIX Awk stdlib库

#!/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]
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.