Ale*_*mov 5 pipe file-descriptor popen python-3.x
在 Popen 中,我可以写入 stdin (0) 并从 stdout (1) 和 stderr (2) 读取。
我想做这样的事情:
#!/usr/bin/env python3
from subprocess import Popen, PIPE
with Popen(
[
'ffmpeg',
'-f', 'matroska', '-i', 'pipe:0',
'-f', 'matroska', '-i', 'pipe:3',
],
stdin=PIPE, in_3=PIPE) as p:
p.stdin.write(b'There is nothing special.')
p.in_3.write(b'\xf0\x9f\x99\x88\xf0\x9f\x99\x89\xf0\x9f\x99\x8a')
Run Code Online (Sandbox Code Playgroud)
stderr,stdout并stdin受到特殊对待。当Popen启动一个新进程时,它必须创建用于与子进程通信的管道,因此指定一个额外的管道与子进程通信并不那么简单。
如果您需要另一个管道,则需要在执行子流程之前对其进行设置。
这是一个简单的示例,向您展示如何做到这一点。它执行一个测试脚本,该脚本仅将数据从作为命令行参数(或 stdin)给出的文件描述符复制到 stderr(或 stdout):
测试.sh:
#!/bin/bash
read_fd="$1" # get file descriptor from command line
cat # write stdin to stdout
cat <&"$read_fd" >&2 # read from read_fd and write to stderr
Run Code Online (Sandbox Code Playgroud)
调用程序:ptest.py:
import os
import subprocess
pipe_rfd, pipe_wfd = os.pipe()
print(pipe_rfd, pipe_wfd)
p = subprocess.Popen(
["./test.sh", str(pipe_rfd)],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=False, # make sure file descriptors are kept open in subprocess
preexec_fn = lambda: os.close(pipe_wfd) # make sure write end is closed in child
)
p.stdin.write(b'spam\n')
p.stdin.close()
os.write(pipe_wfd, b'eggs\n')
os.close(pipe_wfd)
print('out:', p.stdout.read())
print('err:', p.stderr.read())
Run Code Online (Sandbox Code Playgroud)
在 python2 中,您需要在生成子级之前close_fds=False关闭preexec_fn管道的写入端,否则如果写入端在父级中关闭,则读取端将不会看到 EOF。从 python3.2 开始,您可以使用新pass_fds参数来提供要保持打开状态的文件描述符列表,但上面的代码也可以工作(仅在 Linux 上测试)。
应用于您的问题,Popen调用将如下所示:
...
with Popen(
[
'ffmpeg',
'-f', 'matroska', '-i', 'pipe:0',
'-f', 'matroska', '-i', 'pipe:%d' % pipe_rfd,
],
stdin=PIPE, pass_fds=[pipe_rfd]) as p:
...
Run Code Online (Sandbox Code Playgroud)