简体   繁体   English

创建并管道类似文件的对象作为命令的输入

[英]Create and pipe a file-like object as input for a command

I'm looking for a better way to do this, if possible: 如果可能的话,我正在寻找更好的方法来做到这一点:

import subprocess

f = open('temp.file', 'w+')
f.write('hello world')
f.close()

out = subprocess.check_output(['cat', 'temp.file'])

print out

subprocess.check_output(['rm', 'temp.file'])

In this example I'm creating a file and passing it as input to cat (in reality it's not cat I'm running but some other program that parses an input pcap file). 在这个例子中,我正在创建一个文件并将其作为输入传递给cat (实际上它不是我正在运行的cat而是一些其他解析输入pcap文件的程序)。

What I'm wondering is, is there a way in Python I can create a 'file-like object' with some content, and pipe this file-like object as input to a command-line program. 我想知道的是,在Python中是否有一种方法我可以使用一些内容创建一个“类文件对象”,并将这个类文件对象作为输入传递给命令行程序。 If it is possible, I reckon it would be more efficient than writing a file to the disk and then deleting that file. 如果有可能,我认为它比将文件写入磁盘然后删除该文件更有效。

If the program is configured to read from stdin , you can use Popen.communicate : 如果程序配置为从stdin读取,则可以使用Popen.communicate

>>> from subprocess import Popen, PIPE
>>> p = Popen('cat', stdout=PIPE, stdin=PIPE, stderr=PIPE)
>>> out, err = p.communicate(input=b"Hello world!")
>>> out
'Hello world!'

check_output takes a stdin input argument to specify a file-like object to connect to the process's standard input. check_output采用stdin输入参数来指定类似文件的对象以连接到进程的标准输入。

with open('temp.file') as input:
    out = subprocess.check_output(['cat'], stdin=input)

Also, there's no need to shell out to run rm ; 而且,没有必要支持运行rm ; you can remove the file directly from Python: 您可以直接从Python中删除该文件:

os.remove('temp.file')

You can write to a TemporaryFile 您可以写入TemporaryFile

import subprocess
from tempfile import TemporaryFile
f = TemporaryFile("w")
f.write("foo")
f.seek(0)
out = subprocess.check_output(['cat'],stdin=f)

print(out)
b'foo'

If you just want to write to a file like object and get the content: 如果你只想写一个像object这样的文件并获取内容:

from io import StringIO
f = StringIO()
f.write("foo")

print(f.getvalue())

If the command accepts only filenames, if it doesn't read input from its stdin ie, if you can't use stdin=PIPE + .communicate() or stdin=real_file then you could try /dev/fd/# filenames: 如果命令只接受文件名,如果它不读取其stdin的输入,即如果你不能使用stdin=PIPE + .communicate()stdin=real_file那么你可以尝试/dev/fd/# stdin=real_file

#!/usr/bin/env python3
import os
import subprocess
import threading

def pump_input(pipe):
    with pipe:
        for i in range(3):
            print(i, file=pipe)

r, w = os.pipe()
try:
    threading.Thread(target=pump_input, args=[open(w, 'w')]).start()
    out = subprocess.check_output(['cat', '/dev/fd/'+str(r)], pass_fds=[r])
finally:
    os.close(r)
print('got:', out)

No content touches the disk. 没有内容触及磁盘。 The input is passed to the subprocess via the pipe directly. 输入直接通过管道传递给子进程。

If you have a file-like object that is not a real file (otherwise, just pass its name as the command-line argument) then pump_input() could look like: 如果你有一个类似文件的对象不是真正的文件(否则,只是将其名称作为命令行参数传递),那么pump_input()可能如下所示:

import shutil

def pump_input(pipe):
    with pipe:
        shutil.copyfileobj(file_like_object, pipe)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM