Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 对文件中两个模式之间的行进行递归排序_Bash_Awk_Sed_Grep - Fatal编程技术网

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
是一个非常好的主意!大多数时候,我编写这种脚本只是为了一次使用。。。所以不要花太多的时间来改进它们。。。但下次我会尝试你的建议!泰蒂