遍历 linux 在 python 中排序输出

Iterate through linux sort output in python

我无法找到一个解决方案来利用 linux sort 命令作为我的 python 脚本的输入。

例如,我想遍历 sort -mk1 <(cat file1.txt) <(cat file2.txt))

的结果

通常我会使用 Popen 并使用 nextstdout.readline() 遍历它,例如:

import os
import subprocess

class Reader():
    def __init__(self):
        self.proc = subprocess.Popen(['sort -mk1', '<(', 'cat file1.txt', ')', '<(', 'cat file2.txt', ')'], stdout=subprocess.PIPE)

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            line = self.proc.stdout.readline()
            if not line:
                raise StopIteration
            return line


p = Reader()
for line in p:
    # only print certain lines based on some filter 

使用上面的方法,我会得到一个错误:No such file or directory: 'sort -mk1'

经过一些研究,我想我不能使用 Popen,必须使用 os.execl 来利用 bin/bash

所以现在我在下面尝试:

import os
import subprocess

class Reader():
    def __init__(self):
        self.proc = os.execl('/bin/bash', '/bin/bash', '-c', 'set -o pipefail; sort -mk1 <(cat file1.txt) <(cat file2.txt)')

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            line = self.proc.stdout.readline()
            if not line:
                raise StopIteration
            return line


p = Reader()
for line in p:
    # only print certain lines based on some filter 

问题在于它实际上会立即打印所有行。我想一个解决方案是将其结果通过管道传输到一个文件,然后在 python 中遍历该文件。但我真的不想将它保存到文件中然后过滤它,这似乎是不必要的。是的,我可以使用其他 linux 命令,例如 awk,但我想使用 python 进行进一步处理。

所以问题是:

  1. 有没有办法使 Popen 的解决方案有效?
  2. 如何使用第二种解决方案遍历 sort 的输出?

我不明白你为什么要做sort -mk1 $(cat file),排序可以对文件进行操作。看看 check_output。这会让你的生活变得简单

output=subprocess.check_output('ls')
for line in output:
    print(line)

当然,您必须处理异常,手册页中有详细信息

你的脚本中有很多问题。

首先,您的 Popen 将无法工作,原因有以下几个:

  1. 第一个参数应该是 运行 的命令,而你传递了 sort -mk 并且没有这样的文件。您应该简单地传递 sort,并将 -mk 作为参数传递。
  2. 进程替换 <( command ) 是由 shell 处理的事情,为此它正在执行类似 运行 的命令,创建 FIFO 并替换它作为 FIFO 的名称。将这些直接传递给 sort 是行不通的。 sort 可能只会将 <( 视为文件名。

您使用 os.exec* 的第二种方法也不会奏效,因为 os.exec* 将取代您当前的流程。因此它永远不会继续您的 Python 脚本中的下一条语句。

在您的情况下,似乎没有理由使用进程替换。为什么你不能简单地做一些像 subprocess.Popen(['sort', '-mk', 'filename1', 'filename2']) 这样的事情?

如果要使用 shell 功能,则必须使用 shell=True。如果您想使用 Bash 功能,您必须确保 shell 您 运行 是 Bash。

        self.proc = subprocess.Popen(
            'sort -mk1 <(cat file1.txt) <(cat file2.txt)',
            stdout=subprocess.PIPE,
            shell=True,
            executable='/bin/bash')

注意 shell=True Popen 和 friends 的第一个参数是单个字符串(反之亦然;如果没有 shell=True,则必须解析命令自己插入标记)。

当然,cats are useless,但是如果您将它们替换为 shell 可以轻松优雅地执行并且您无法轻易用本机 Python 代码替换的东西,这可能是要走的路。

简而言之,<(command)是一个Bash进程替换; shell 将在子进程中 运行 command ,并将参数替换为进程生成其输出的打开文件句柄的设备名称。所以 sort 会看到类似

的内容
sort -mk /dev/fd/63 /dev/fd/64

其中 /dev/fd/63 是第一个命令的输出可用的管道,/dev/fd/64 是另一个命令的标准输出的读取端。