遍历 linux 在 python 中排序输出
Iterate through linux sort output in python
我无法找到一个解决方案来利用 linux sort
命令作为我的 python 脚本的输入。
例如,我想遍历 sort -mk1 <(cat file1.txt) <(cat file2.txt))
的结果
通常我会使用 Popen
并使用 next
和 stdout.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 进行进一步处理。
所以问题是:
- 有没有办法使
Popen
的解决方案有效?
- 如何使用第二种解决方案遍历
sort
的输出?
我不明白你为什么要做sort -mk1 $(cat file),排序可以对文件进行操作。看看 check_output。这会让你的生活变得简单
output=subprocess.check_output('ls')
for line in output:
print(line)
当然,您必须处理异常,手册页中有详细信息
你的脚本中有很多问题。
首先,您的 Popen
将无法工作,原因有以下几个:
- 第一个参数应该是 运行 的命令,而你传递了
sort -mk
并且没有这样的文件。您应该简单地传递 sort
,并将 -mk
作为参数传递。
- 进程替换
<( 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
,则必须解析命令自己插入标记)。
当然,cat
s are useless,但是如果您将它们替换为 shell 可以轻松优雅地执行并且您无法轻易用本机 Python 代码替换的东西,这可能是要走的路。
简而言之,<(command)
是一个Bash进程替换; shell 将在子进程中 运行 command
,并将参数替换为进程生成其输出的打开文件句柄的设备名称。所以 sort
会看到类似
的内容
sort -mk /dev/fd/63 /dev/fd/64
其中 /dev/fd/63
是第一个命令的输出可用的管道,/dev/fd/64
是另一个命令的标准输出的读取端。
我无法找到一个解决方案来利用 linux sort
命令作为我的 python 脚本的输入。
例如,我想遍历 sort -mk1 <(cat file1.txt) <(cat file2.txt))
通常我会使用 Popen
并使用 next
和 stdout.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 进行进一步处理。
所以问题是:
- 有没有办法使
Popen
的解决方案有效? - 如何使用第二种解决方案遍历
sort
的输出?
我不明白你为什么要做sort -mk1 $(cat file),排序可以对文件进行操作。看看 check_output。这会让你的生活变得简单
output=subprocess.check_output('ls')
for line in output:
print(line)
当然,您必须处理异常,手册页中有详细信息
你的脚本中有很多问题。
首先,您的 Popen
将无法工作,原因有以下几个:
- 第一个参数应该是 运行 的命令,而你传递了
sort -mk
并且没有这样的文件。您应该简单地传递sort
,并将-mk
作为参数传递。 - 进程替换
<( 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
,则必须解析命令自己插入标记)。
当然,cat
s are useless,但是如果您将它们替换为 shell 可以轻松优雅地执行并且您无法轻易用本机 Python 代码替换的东西,这可能是要走的路。
简而言之,<(command)
是一个Bash进程替换; shell 将在子进程中 运行 command
,并将参数替换为进程生成其输出的打开文件句柄的设备名称。所以 sort
会看到类似
sort -mk /dev/fd/63 /dev/fd/64
其中 /dev/fd/63
是第一个命令的输出可用的管道,/dev/fd/64
是另一个命令的标准输出的读取端。