Я делаю вызов программы из оболочки, используя модуль подпроцесса, который выводит двоичный файл в STDOUT.
Я использую Popen() для вызова программы, а затем хочу передать поток функции в пакет Python (называемый "pysam"), который, к сожалению, не может содержать объекты Python, но может читать из STDIN. Так что я хотел бы сделать, так это вывод команды оболочки из STDOUT в STDIN.
Как это можно сделать из модуля Popen/subprocess? Так я вызываю программу оболочки:
p = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shell=True).stdout
Это будет читать вывод "my_cmd" STDOUT и получить поток к нему в p. Поскольку мой модуль Python не может напрямую читать "p", я пытаюсь перенаправить STDOUT "my_cmd" обратно в 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 - это проблема, а не последующие шаги.
EDIT: В ответ на ответы я попытался:
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"). Любая идея почему?
Любая идея, как это можно исправить?
EDIT 2: Я добавляю ссылку на документацию Pysam, если она помогает, я действительно не могу понять это. Страница документации:
http://wwwfgu.anat.ox.ac.uk/~andreas/documentation/samtools/usage.html
и конкретная заметка о потоках находится здесь:
http://wwwfgu.anat.ox.ac.uk/~andreas/documentation/samtools/usage.html#using-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. Следующий скрипт преобразует отформатированный файл BAM на stdin в форматированный файл SAM на stdout:
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, если используете stdout=subprocess.PIPE
, однако общая проблема заключается в том, что вам нужно работать с sys.stdin
если вы хотите обмануть pysam в его использовании.
Например:
sys.stdin = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shell=True).stdout
s = pysam.Samfile("-", "rb")
sys.stdin = sys.__stdin__ # restore original stdin
UPDATE: Предполагается, что pysam работает в контексте интерпретатора Python и, следовательно, означает интерпретатор Python stdin, когда указан параметр "-". К сожалению, это не так; когда указано "-", он считывается непосредственно из дескриптора файла 0.
Другими словами, он не использует концепцию python для stdin (sys.stdin), поэтому ее замена не влияет на pysam.Samfile(). Также невозможно взять вывод из вызова Popen и как-то "надавить" его на дескриптор файла 0; это только для чтения, а другой конец - к вашему терминалу.
Единственный реальный способ получить этот вывод в файловом дескрипторе 0 - просто переместить его в дополнительный скрипт и соединить два вместе с первым. Это гарантирует, что вывод из Popen в первом скрипте закончится на дескриптор файла 0 второго.
Итак, в этом случае ваш лучший вариант - разделить это на два сценария. Первый вызовет my_cmd и выведет его вывод и будет использовать его для ввода второго Popen другого скрипта Python, который вызывает pysam.Samfile("-", "rb").
sys.stdin
(см. Мой комментарий к основному сообщению).
В конкретном случае работы с pysam я смог обойти проблему, используя именованный канал (http://docs.python.org/library/os.html#os.mkfifo), который является каналом, который может быть доступ как обычный файл. В общем, вы хотите, чтобы потребитель (читатель) трубы слушал, прежде чем начинать писать в трубу, чтобы вы ничего не пропустили. Тем не менее, pysam.Samfile("-", "rb") будет зависать, как вы отметили выше, если на stdin уже ничего не зарегистрировано.
Предполагая, что вы имеете дело с предварительным вычислением, которое занимает достаточное количество времени (например, сортировка бара перед его передачей в pysam), вы можете начать это предварительное вычисление, а затем прослушивать поток до того, как что-либо получится:
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)
/dev/fd/#
имена файлов .
Если ваша система поддерживает его; вы можете использовать /dev/fd/#
имена файлов:
process = subprocess.Popen(args, stdout=subprocess.PIPE)
samfile = pysam.Samfile("/dev/fd/%d" % process.stdout.fileno(), "rb")
import sys
,sys.stdin.write(p.stdout.read())
? Убедитесь, чтоs = pysam.Samfile("-", "rb")
перед записью в stdin ..