连续段落的分组排序(以空行分隔)?

syn*_*ror 8 text-processing sort

我想我现在在按排序方面很有经验;但是,到目前为止,我还没有找到任何如何对连续行进行排序的信息。

假设我们有一个看起来像这样的文本文件:(当然非常简化)

Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot
Run Code Online (Sandbox Code Playgroud)

现在,是否可以分别按每个块的字母数字对行进行排序?我的意思是,结果看起来像这样:

Alpha
Charlie
Delta
Echo

Bravo
Foxtrot
Golf
Hotel
Run Code Online (Sandbox Code Playgroud)

从我在sort手册页中找到的内容来看,内置的 UNIXsort命令可能无法做到这一点。或者甚至可以在不必求助于外部/第三方工具的情况下完成?

Dra*_*oan 9

awk -v RS= -v cmd=sort '{print | cmd; close(cmd); print ""}' file
Run Code Online (Sandbox Code Playgroud)

将记录分隔符设置为RS空字符串会使 awk 一次进入段落。对于每个段落,将段落 (in $0) 通过管道传输到 cmd(设置为sort)并打印输出。打印一个空行,用print "".

如果我们给出 perl 示例,那么我将提供一种替代方法而不是 Stephane 的方法:

perl -e 'undef $/; print join "\n", sort (split /\n/), "\n" 
    foreach(split(/\n\n/, <>))' < file
Run Code Online (Sandbox Code Playgroud)

取消设置字段分隔符 ( undef $/),这允许我们使用<>和获取整个 STDIN。我们接着split\n\n(段落)。foreach“段落”,sort这些行通过split围绕换行符sorting,然后将join它们重新组合在一起并在尾随\n.

但是,这有一个副作用,即在最后一段添加“尾随段落”分隔符(如果之前没有)。你可以用稍微不那么漂亮的方式解决这个问题:

perl -e 'undef $/; print join "\n", sort (split /\n/) , (\$_ == \$list[-1] ? "" : "\n")
    foreach(@list = split(/\n\n/, <>))' < file
Run Code Online (Sandbox Code Playgroud)

这将段落分配给@list,然后有一个“三元运算”来检查它是否是foreach\$_ == \$list[-1]检查)的最后一个元素。打印""如果是(? ...),其他(: ...)打印"\n"了所有其他的“段落”(元素@list)。


Sté*_*las 9

Drav 的awk解决方案很好,但这意味着sort每段运行一个命令。为避免这种情况,您可以这样做:

< file awk -v n=0 '!NF{n++};{print n,$0}' | sort -k1n -k2 | cut -d' ' -f2-
Run Code Online (Sandbox Code Playgroud)

或者你可以在perl

perl -ne 'if (/\S/){push@l,$_}else{print sort@l if@l;@l=();print}
          END{print sort @l if @l}' < file
Run Code Online (Sandbox Code Playgroud)

请注意,上面的分隔符是空行(对于awk一个,只有空格或制表符的行,对于perl一个,任何水平或垂直间距字符)而不是空行。如果确实需要空行,可以替换!NF!length$0=="",并替换/\S//./


Rai*_*ahs 5

我用 Haskell 编写了一个工具,它允许您对文本段落使用 sort、shuf、tac 或任何其他命令。

https://gist.github.com/siers/01306a361c22f2de0122
编辑:该工具也包含在此 repo 中:https : //github.com/siers/haskell-import-sort

它将文本分成块,用\0字符连接子块,通过命令管道,最后反向执行相同的操作。

28-08-2015:我发现了这个工具的另一个个人用途——在一行后选择 N 个段落。

paramap grep -aA2 '^reddit usernames' < ~/my-username-file
reddit usernames

foo
bar
baz

a couple
more of these
Run Code Online (Sandbox Code Playgroud)