如何对线组进行排序?

时间:2012-11-23 00:36:22

标签: bash sorting

在以下示例中,有3个元素必须排序:

  1. “[aaa]”和它下面的4行(总是4行)形成一个单元。
  2. “[kkk]”和它下面的4行(总是4行)组成一个单元。
  3. “[zzz]”和它下面的4行(总是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.
    

3 个答案:

答案 0 :(得分: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。

答案 1 :(得分:1)

假设其他行中不包含[

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个命令完成。其他线路是保留标题和页脚。

我也假设,在标题和&amp;之间首先“[section]”没有其他行。

答案 2 :(得分:0)

这可能适合你(GNU sed&amp; 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