首页 > 解决方案 > 递归地对文件中两个模式之间的行进行排序

问题描述

我有以下格式的文件

3
Lattice="89.8218778092 0.0 0.0 0.0 15.8543061924 0.0 0.0 0.0 25.203816" Properties=id:I:1:species:S:1:
1 1 -0.00119157 -5.67557e-05 -1.49279e-04
2 3 0.00220589 -0.00133867 9.67397e-04
3 2 -5.43822e-04 -0.00119676 -8.99064e-05
3
Lattice="89.8218778092 0.0 0.0 0.0 15.8543061924 0.0 0.0 0.0 25.203816" Properties=id:I:1:species:S:1:
1 1 -0.00119157 -5.67557e-05 -1.49279e-04
2 3 0.00220589 -0.00133867 9.67397e-04
3 2 -5.43822e-04 -0.00119676 -8.99064e-05

我希望能够根据第二列对文件的内容进行排序,而无需修改类似于以下应始终保持原位的行

3
Lattice="89.8218778092 0.0 0.0 0.0 15.8543061924 0.0 0.0 0.0 25.203816" Properties=id:I:1:species:S:1:

预期产出

3
Lattice="89.8218778092 0.0 0.0 0.0 15.8543061924 0.0 0.0 0.0 25.203816" Properties=id:I:1:species:S:1:
1 1 -0.00119157 -5.67557e-05 -1.49279e-04
3 2 -5.43822e-04 -0.00119676 -8.99064e-05
2 3 0.00220589 -0.00133867 9.67397e-04
3
Lattice="89.8218778092 0.0 0.0 0.0 15.8543061924 0.0 0.0 0.0 25.203816" Properties=id:I:1:species:S:1:
1 1 -0.00119157 -5.67557e-05 -1.49279e-04
3 2 -5.43822e-04 -0.00119676 -8.99064e-05
2 3 0.00220589 -0.00133867 9.67397e-04

我试过有没有办法在 UNIX 排序中忽略标题行? 但没有按预期进行。

我想在 BASH 中这样做。

标签: bashawksedgrep

解决方案


这在 Bash 或传统的面向行的 Unix 实用程序中比较棘手,但在 GNU Awk 或 Python 等现代脚本语言中几乎很容易。

#!/usr/bin/env python3
import sys

section = []
lattice = False

def sort_em(lines):
    return ''.join(sorted(lines, key=lambda x: tuple(map(float, x.split()[2:4]))))

def print_em(*lines):
    print(*lines, end='')

for line in sys.stdin:
    if line.startswith('1080\n'):
        if section:
            print_em(sort_em(section))
            section = []
        lattice = True
        print_em(line)
    elif lattice:
        if not line.startswith('Lattice="'):
            raise ValueError('Expected Lattice="..." but got %s' % line)
        lattice = False
        print_em(line)
    else:
        section.append(line)
if section:
    print_em(sort_em(section))

您可以将其保存在您的PATH, 和chmod a+x它的文件中。如果你调用它sortsections,你会像这样运行它

sortsections filename >newfile

读取行filename并将其输出以newfile根据要求进行排序。

演示:https ://ideone.com/7RRvXQ

tuple(map(float ...))事物提取我们想要排序的字段,将它们全部转换为 ,并将它们float收集到一个tuple. (有点晦涩,map返回一个生成器对象,所以我们必须通过调用tuple()它来生成结果。)print包装器避免了end=''每次我们想要打印某些东西时都必须重复。(我们阅读的每行已经有一个尾随换行符,但print没有end=''会添加另一个。)

这硬编码1080为新部分的标记;将其更改为读取第一行然后将其用作所有后续部分的标记并不难,和/或计算每个部分包含那么多行,并在您消耗完行数时读取新计数在每个标题部分中指出。


推荐阅读