使用Python子进程将stdout重定向到stdin?
我正在使用子进程模块从shell调用一个程序,该模块将二进制文件输出到STDOUT 我使用Popen调用该程序,然后我想将流传递给一个名为pysam的Python包中的函数,不幸的是,该函数不能读取Python文件对象,但可以从STDIN读取。所以我想做的是让shell命令的输出从STDOUT转到STDIN 如何在Popen/子流程模块中实现这一点?这是我调用shell程序的方式:使用Python子进程将stdout重定向到stdin?,python,shell,unix,streaming,subprocess,Python,Shell,Unix,Streaming,Subprocess,我正在使用子进程模块从shell调用一个程序,该模块将二进制文件输出到STDOUT 我使用Popen调用该程序,然后我想将流传递给一个名为pysam的Python包中的函数,不幸的是,该函数不能读取Python文件对象,但可以从STDIN读取。所以我想做的是让shell命令的输出从STDOUT转到STDIN 如何在Popen/子流程模块中实现这一点?这是我调用shell程序的方式: p = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shel
p = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shell=True).stdout
这将读取my_cmd的STDOUT输出,并在p中获得一个流。由于我的Python模块无法直接从p读取,因此我尝试使用以下命令将我的_cmd的STDOUT重定向回STDIN:
p = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True).stdout
然后我调用我的模块,该模块使用-作为STDIN的占位符:
s = pysam.Samfile("-", "rb")
上面的调用只意味着从STDIN读取,并将其作为二进制文件rb读取
当我尝试这一点时,我只是将二进制输出发送到屏幕上,而Samfile函数似乎无法读取它。即使我删除了对Samfile的调用,也会发生这种情况,因此我认为问题出在我对Popen的调用上,而不是下游步骤
编辑:在回答问题时,我尝试:
sys.stdin = subprocess.Popen(tagBam_cmd, stdout=subprocess.PIPE, shell=True).stdout
print "Opening SAM.."
s = pysam.Samfile("-","rb")
print "Done?"
sys.stdin = sys.__stdin__
这似乎很难解决。我得到输出:
Opening SAM..
但它永远不会超过Samfile-,rb行。知道为什么吗
你知道怎么解决这个问题吗
编辑2:我正在添加一个Pysam文档的链接,以防它有所帮助,我真的无法理解这一点。文档页面为:
关于streams的具体说明如下:
特别是:
Pysam不支持从真正的python文件对象读写,但它支持从stdin和stdout读写。以下示例从stdin读取并写入stdout:
infile = pysam.Samfile( "-", "r" )
outfile = pysam.Samfile( "-", "w", template = infile )
for s in infile: outfile.write(s)
它还可以处理BAM文件。以下脚本将stdin上的BAM格式文件转换为stdout上的SAM格式文件:
infile = pysam.Samfile( "-", "rb" )
outfile = pysam.Samfile( "-", "w", template = infile )
for s in infile: outfile.write(s)
注意,只有文件打开模式需要从r更改为rb。
所以我只想获取来自Popen的流,它读取stdout,并将其重定向到stdin,这样我就可以使用Samfile-,rb,因为上面的部分状态是可能的
谢谢。如果您使用的是stdout=subprocess.PIPE,您会在stdout上看到二进制文件,这让我有点困惑。但是,总体问题是,如果您想欺骗pysam使用它,您需要使用sys.stdin 例如:
sys.stdin = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shell=True).stdout
s = pysam.Samfile("-", "rb")
sys.stdin = sys.__stdin__ # restore original stdin
更新:假设pysam是在Python解释器的上下文中运行的,因此在指定时表示Python解释器的stdin。不幸的是,事实并非如此;当指定-时,它直接从文件描述符0读取
换句话说,它没有使用Python的stdinsys.stdin概念,因此替换它对pysam.Samfile没有影响。也不可能从Popen调用获取输出并以某种方式将其推送到文件描述符0;它是只读的,另一端连接到终端
将该输出放到文件描述符0上的唯一实际方法是将其移动到另一个脚本,并从第一个脚本开始将这两个脚本连接在一起。这确保了第一个脚本中Popen的输出将在第二个脚本的文件描述符0上结束
因此,在本例中,最好的选择是将其拆分为两个脚本。第一个将调用my_cmd并获取该命令的输出,并将其用作另一个Python脚本的第二个Popen的输入,该脚本调用pysam.Samfile-,rb。如果使用stdout=subprocess.PIPE,您会在stdout上看到二进制文件,但我有点困惑,总的问题是,如果要诱使pysam使用sys.stdin,就需要使用它 例如:
sys.stdin = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shell=True).stdout
s = pysam.Samfile("-", "rb")
sys.stdin = sys.__stdin__ # restore original stdin
更新:假设pysam是在Python解释器的上下文中运行的,因此在指定时表示Python解释器的stdin。不幸的是,事实并非如此;当指定-时,它直接从文件描述符0读取
换句话说,它没有使用Python的stdinsys.stdin概念,因此替换它对pysam.Samfile没有影响。也不可能从Popen调用获取输出并以某种方式将其推送到文件描述符0;它是只读的,另一端连接到终端
将该输出放到文件描述符0上的唯一实际方法是将其移动到另一个脚本,并从第一个脚本开始将这两个脚本连接在一起。这确保了第一个脚本中Popen的输出将在第二个脚本的文件描述符0上结束
因此,在本例中,最好的选择是将其拆分为两个脚本。第一个将调用my_cmd并获取该命令的输出,并将其用作另一个Python脚本的第二个Popen的输入,该脚本调用pysam.Samfile-,rb。在处理pysam的特定情况下,我能够使用命名管道解决该问题http://docs.python.org/library/os.htmlos.mkfifo,这是一个可以像普通文件一样访问的管道。总的来说,哟 您希望管道的用户读者在您开始向管道写入内容之前倾听,以确保您不会遗漏任何内容。但是,如果stdin上没有注册任何内容,pysam.Samfile-,rb将挂起,如上所述 假设您正在处理需要相当长时间的先前计算,例如,在将bam传递到pysam之前对bam进行排序,您可以启动该先前计算,然后在任何内容得到输出之前监听流:
import os
import tempfile
import subprocess
import shutil
import pysam
# Create a named pipe
tmpdir = tempfile.mkdtemp()
samtools_prefix = os.path.join(tmpdir, "namedpipe")
fifo = samtools_prefix + ".bam"
os.mkfifo(fifo)
# The example below sorts the file 'input.bam',
# creates a pysam.Samfile object of the sorted data,
# and prints out the name of each record in sorted order
# Your prior process that spits out data to stdout/a file
# We pass samtools_prefix as the output prefix, knowing that its
# ending file will be named what we called the named pipe
subprocess.Popen(["samtools", "sort", "input.bam", samtools_prefix])
# Read from the named pipe
samfile = pysam.Samfile(fifo, "rb")
# Print out the names of each record
for read in samfile:
print read.qname
# Clean up the named pipe and associated temp directory
shutil.rmtree(tmpdir)
在处理pysam的具体案例中,我能够使用命名管道解决这个问题http://docs.python.org/library/os.htmlos.mkfifo,这是一个可以像普通文件一样访问的管道。一般来说,您希望管道的消费者读者在开始向管道写入内容之前倾听,以确保不会遗漏任何内容。但是,如果stdin上没有注册任何内容,pysam.Samfile-,rb将挂起,如上所述 假设您正在处理需要相当长时间的先前计算,例如,在将bam传递到pysam之前对bam进行排序,您可以启动该先前计算,然后在任何内容得到输出之前监听流:
import os
import tempfile
import subprocess
import shutil
import pysam
# Create a named pipe
tmpdir = tempfile.mkdtemp()
samtools_prefix = os.path.join(tmpdir, "namedpipe")
fifo = samtools_prefix + ".bam"
os.mkfifo(fifo)
# The example below sorts the file 'input.bam',
# creates a pysam.Samfile object of the sorted data,
# and prints out the name of each record in sorted order
# Your prior process that spits out data to stdout/a file
# We pass samtools_prefix as the output prefix, knowing that its
# ending file will be named what we called the named pipe
subprocess.Popen(["samtools", "sort", "input.bam", samtools_prefix])
# Read from the named pipe
samfile = pysam.Samfile(fifo, "rb")
# Print out the names of each record
for read in samfile:
print read.qname
# Clean up the named pipe and associated temp directory
shutil.rmtree(tmpdir)
如果您的系统支持它;你可以:
如果您的系统支持它;你可以:
导入sys,sys.stdin.writep.stdout.read?在写入stdin之前,请确保s=pysam.Samfile-,rb。您仍然看到屏幕上的二进制输出吗?换句话说,你确定你的tagBam_cmd真的在将结果发送到stdout吗?我没有看到二进制屏幕,我只是看到程序挂起。当我运行tagBam_cmd的内容时,它会将其打印到屏幕上,因此我假设它是标准输出。如何检查呢?在shell中以:tagBam\u cmd>test\u输出的形式运行tagBam\u cmd,看看二进制文件是否在文件中结束。如果没有,那么它可能会转到stderr。我已经这样做了,它肯定会转到文件。import sys,sys.stdin.writep.stdout.read?在写入stdin之前,请确保s=pysam.Samfile-,rb。您仍然看到屏幕上的二进制输出吗?换句话说,你确定你的tagBam_cmd真的在将结果发送到stdout吗?我没有看到二进制屏幕,我只是看到程序挂起。当我运行tagBam_cmd的内容时,它会将其打印到屏幕上,因此我假设它是标准输出。如何检查呢?在shell中以:tagBam\u cmd>test\u输出的形式运行tagBam\u cmd,看看二进制文件是否在文件中结束。如果没有,那么它可能会转到stderr。我已经这样做了,它肯定会转到文件。虽然我更喜欢只写sys.stdin,而不是在主帖子上看到我的评论。这是行不通的。您将尝试写入只读的文件流对象,而不是为将来的读取推送数据。现在,如果你打开/dev/fd/0并写信给它,如果可以的话。@DavidK.Hess:我试过你的建议,但它似乎挂在Samfile上。。。对你有用吗?请参阅“编辑到我的原始帖子”。@user248237查看我的编辑-您确定pyasm正在从解释器的stdin读取数据,还是正在运行带有这些参数的外部程序?指向pyasm.Samfile文档的链接也会有所帮助。@DavidK.Hess:添加链接。相关部分在这里:虽然我更喜欢只写信给sys.stdin,而不是在主要帖子上看到我的评论。这是行不通的。您将尝试写入只读的文件流对象,而不是为将来的读取推送数据。现在,如果你打开/dev/fd/0并写信给它,如果可以的话。@DavidK.Hess:我试过你的建议,但它似乎挂在Samfile上。。。对你有用吗?请参阅“编辑到我的原始帖子”。@user248237查看我的编辑-您确定pyasm正在从解释器的stdin读取数据,还是正在运行带有这些参数的外部程序?指向pyasm.Samfile文档的链接也会有所帮助。@DavidK.Hess:添加链接。相关部分在这里:如果系统支持它,那么它可能更容易实现。如果系统支持它,那么它可能更容易实现。