bash - 递归地对文件中两个模式之间的行进行排序
问题描述
我有以下格式的文件
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 中这样做。
解决方案
这在 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
根据要求进行排序。
该tuple(map(float ...))
事物提取我们想要排序的字段,将它们全部转换为 ,并将它们float
收集到一个tuple
. (有点晦涩,map
返回一个生成器对象,所以我们必须通过调用tuple()
它来生成结果。)print
包装器避免了end=''
每次我们想要打印某些东西时都必须重复。(我们阅读的每行已经有一个尾随换行符,但print
没有end=''
会添加另一个。)
这硬编码1080
为新部分的标记;将其更改为读取第一行然后将其用作所有后续部分的标记并不难,和/或计算每个部分包含那么多行,并在您消耗完行数时读取新计数在每个标题部分中指出。
推荐阅读
- c# - 如何在 C# net5.0 中使用 with 关键字将一条记录复制到另一条记录
- java - 无法安装maven,系统无法识别“mvn”命令行
- reactjs - 如何使用 react state 将多个表单数据存储到 antd 表中?
- flutter - 如何理解颤动中的传入约束?
- google-cloud-storage - google cloud CDN always serve my static file through only 1 IP
- c++ - 如何通过winbio API验证面部特征?
- flutter - 使用调试符号时在 Flutter App 中出现 Gradle 错误
- bulk - 将自定义字段添加到高级批量编辑
- c++ - 从数组 C++ 中删除类
- c# - 为什么即使单元测试全部通过,我的代码覆盖率也为零?