Bash 对文件中两个模式之间的行进行递归排序
我有以下格式的文件Bash 对文件中两个模式之间的行进行递归排序,bash,awk,sed,grep,Bash,Awk,Sed,Grep,我有以下格式的文件 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
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
我试过了
但结果并不像预期的那样
我希望在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))
您可以将其保存在路径中的文件中,然后chmod a+x
将其保存。如果您调用它sortsections
,您将像
sortsections filename>newfile
读取filename
中的行,并将其输出到newfile
中,按要求排序
演示:
tuple(map(float…)
东西提取我们想要排序的字段,将它们全部转换为float
,并将它们收集到tuple
。(稍微模糊地,map
返回一个生成器对象,因此我们必须通过调用tuple()
来生成结果。)print
包装器避免了每次我们想要打印某个内容时重复end='
。(我们读到的每一行都已经有了一个尾随的换行符,但是没有结尾的print
会增加另一行。)
该硬编码1080
作为新区段的标记;将其更改为读取第一行,然后将其用作所有后续部分的标记,和/或计算每个部分包含的行数并不困难,当您使用了每个页眉部分中指示的行数时,读取一个新的计数。方法是将大文件拆分为多个仅包含1个单元格的小文件。然后使用链接的方法在每个文件中按所需方式对行进行排序。最后,使用cat
将文件与排序后的数据连接在一起
#!/usr/bin/env bash
nlines=$(head -n 1 $1) # Get the number of lines per each cell
let nlines+=2 # Add to the number of sites the header lines
split -l $nlines -a 5 $1 # Split the file in multiple files each one containing a single cell
for file in ${1}*; do # Sort each file individually
(head -n 2 $file && tail -n +3 $file | sort -k 2) > sorted-$file;
cat sorted-${1}* > $2 # Concatenate all the sorted files
rm sorted-${1}* # Remove the sorted files
将其用作:
script.sh <file_name> <new_file_name>
script.sh
免责声明:我没有对此进行测试,请在一个干净的文件夹中使用原始文件的副本进行尝试。这将生成许多文件,并在最后清理它们
例如,如果您提供一个关于pastylink的真实示例,我可以更好地修改脚本。请在问题中提及您的预期输出示例。同时,在你的问题中保持输入和输出样本的清晰和简短(长度)。实际上,你可能想更改问题的标题,以便在文件中两种模式之间对行进行排序。另外,你的问题定义得很差。您的预期输出根本没有按第一列和第二列排序。预期输出看起来像是按第三列排序的。是来自整个输入文件的那些行,还是仅仅是两个“晶格”行之间的行?@tripleee是的,是来自标题后整个1080行集合的排序行。我不能将所有这些都粘贴到这里。不管您的真实数据中有多少行,您都需要拿出一个以最小方式表示您的问题的方法(例如,5行而不是1800行),以便我们能够帮助您。请看。问题是关于bash解决方案……在通过awk递归提取模式后,有没有办法调用sort?@riccardoperaglia这可以在bash中完成(现在请参见其他答案),但作为一名shell程序员,您需要的技能之一是何时知道何时转换到解决方案自然产生的语言。传统上,您必须学习sed、Awk和shell,但在今天这个时代,对于这个特定的解决方案,我选择了Python,它在许多平台上都非常广泛。(奖励:如果你有受虐癖,它也可以在Windows上运行。)@abhijitdhakane这不是不可能的,但Awk解决方案的问题是它必须依赖外部排序。Python内置了排序
,因此解决方案显而易见且简单明了。(主要的缺点是我必须包装print
以避免写第二行换行。我想我可以用write
来代替。)@tripleee你看到我下面的解决方案了吗?它可能比您的要慢(因为它涉及到创建许多文件),但我在过去使用过很多次,而且编写速度相当快…@abhijit dhakane请告诉我这是否有效…:)可能如果仅仅因为用户传入了一个包含空格或其他shell元字符的文件名而中断,那将是愚蠢的。正确的解决方案是使用mktemp-d
为临时文件创建一个目录,并使用trap
在出现错误或SIGTERM时删除临时目录。@tripleee是的。。。mktemp
+trap
是一个非常好的主意!大多数时候,我编写这种脚本只是为了一次使用。。。所以不要花太多的时间来改进它们。。。但下次我会尝试你的建议!泰蒂