【问题标题】:How to sort groups of lines?如何对多组线进行排序?
【发布时间】:2012-11-23 00:36:21
【问题描述】:

在以下示例中,需要对 3 个元素进行排序:

  1. "[aaa]" 和它下面的 4 行(总是 4)形成一个单元。
  2. "[kkk]" 和它下面的 4 行(总是 4 行)形成一个单元。
  3. "[zzz]" 和它下面的 4 行(总是 4 行)形成一个单元。

只有遵循这种模式的行组才应该被排序; "[aaa]" 之前和 "[zzz]" 的第 4 行之后的任何内容都必须保持不变。

来自:

This sentence and everything above it should not be sorted.

[zzz]
some
random
text
here
[aaa]
bla
blo
blu
bli
[kkk]
1
44
2
88

And neither should this one and everything below it.

到:

This sentence and everything above it should not be sorted.

[aaa]
bla
blo
blu
bli
[kkk]
1
44
2
88
[zzz]
some
random
text
here

And neither should this one and everything below it.

【问题讨论】:

  • 多么可怕的例子......为什么所有部分的值都相同?注意:我会使用awk
  • 编辑:现在应该更容易理解了。
  • 是的,之前和之后的数据插图是要走的路。祝你好运。

标签: bash sorting


【解决方案1】:

也许不是最快的 :) [1] 但它会做你想做的事,我相信:

for line in $(grep -n '^\[.*\]$' sections.txt |
              sort -k2 -t: |
              cut -f1 -d:); do
  tail -n +$line sections.txt | head -n 5
done

这里有一个更好的:

for pos in $(grep -b '^\[.*\]$' sections.txt |
             sort -k2 -t: |
             cut -f1 -d:); do
  tail -c +$((pos+1)) sections.txt | head -n 5
done

[1] 第一个在文件中的行数上类似于 O(N^2),因为它必须一直读取到每个部分的部分。第二个,可以立即找到正确的字符位置,应该更接近O(N log N)。

[2] 这让您相信每个部分中总是正好有五行(标题加上后面的四行),因此head -n 5。但是,如果需要的话,用读取到但不包括以“[”开头的下一行的内容替换它真的很容易。


保留开始和结束需要更多的工作:

# Find all the sections
mapfile indices < <(grep -b '^\[.*\]$' sections.txt)
# Output the prefix
head -c+${indices[0]%%:*} sections.txt
# Output sections, as above
for pos in $(printf %s "${indices[@]}" |
             sort -k2 -t: |
             cut -f1 -d:); do
  tail -c +$((pos+1)) sections.txt | head -n 5
done
# Output the suffix
tail -c+$((1+${indices[-1]%%:*})) sections.txt | tail -n+6

您可能希望从中创建一个函数,或一个脚本文件,将sections.txt 更改为$1。

【讨论】:

  • 它进行排序,但错误地丢弃了页眉和页脚。他们不应受到程序的影响。
  • 保留页眉和页脚的一种方法(另一种方法是先剥离它们,然后在最后添加它们。)
【解决方案2】:

假设其他行不包含[

header=`grep -n 'This sentence and everything above it should not be sorted.' sortme.txt | cut -d: -f1`
footer=`grep -n 'And neither should this one and everything below it.' sortme.txt | cut -d: -f1`

head -n $header sortme.txt #print header

head -n $(( footer - 1 )) sortme.txt | tail -n +$(( header + 1 )) | tr '\n[' '[\n' | sort | tr '\n[' '[\n' | grep -v '^\[$' #sort lines between header & footer
#cat sortme.txt | head -n $(( footer - 1 )) | tail -n +$(( header + 1 )) | tr '\n[' '[\n' | sort | tr '\n[' '[\n' | grep -v '^\[$' #sort lines between header & footer

tail -n +$footer sortme.txt #print footer

达到目的。

请注意,主要的排序工作仅由第 4 个命令完成。其他行用于保留页眉和页脚。

我还假设,在标题和第一个“[section]”之间没有其他行。

【讨论】:

  • 发现cat的无用使用!
  • ^^对不起,那是我测试的时候。忘记改了。
【解决方案3】:

这可能对你有用(GNU sed & sort):

sed -i.bak '/^\[/!b;N;N;N;N;s/\n/UnIqUeStRiNg/g;w sort_file' file
sort -o sort_file sort_file
sed -i -e '/^\[/!b;R sort_file' -e 'd' file
sed -i 's/UnIqUeStRiNg/\n/g' file

排序后的文件将位于file,原始文件位于file.bak

这将按排序顺序显示以 [ 开头的所有行和以下 4 行。

UnIqUeStRiNg 可以是任何不包含换行符的唯一字符串,例如\x00

【讨论】:

  • 你忘记了页眉和页脚...This sentence and everything above it should not be sorted.
  • @anishsane 来自您提供的示例数据,页眉和页脚未排序。但是,如果文件的这些部分可能包含以 [...] 开头的行,那么 sed 命令可以更具体,即 /^\[\(aaa\|\kkk\|zzz\)\]/!b
猜你喜欢
  • 2017-07-03
  • 1970-01-01
  • 2021-07-02
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 2014-05-13
  • 1970-01-01
  • 2014-01-21
相关资源
最近更新 更多