杀死 python ffmpeg 子进程会破坏 cli 输出
Posted
技术标签:
【中文标题】杀死 python ffmpeg 子进程会破坏 cli 输出【英文标题】:Killing python ffmpeg subprocess breaks cli output 【发布时间】:2012-05-22 01:26:39 【问题描述】:我正在尝试使用子进程执行系统命令并读取输出。
但是如果命令花费超过 10 秒,我想杀死子进程。
我尝试了多种方法。
我最后一次尝试的灵感来自这篇文章:https://***.com/a/3326559/969208
例子:
import os
import signal
from subprocess import Popen, PIPE
class Alarm(Exception):
pass
def alarm_handler(signum, frame):
raise Alarm
def pexec(args):
p = Popen(args, stdout=PIPE, stderr=PIPE)
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(10)
stdout = stderr = ''
try:
stdout, stderr = p.communicate()
signal.alarm(0)
except Alarm:
try:
os.kill(p.pid, signal.SIGKILL)
except:
pass
return (stdout, stderr)
问题是:程序退出后,cli 中不会显示任何字符,直到我点击返回。并且点击返回不会给我一个新的线路。
我想这与 stdout 和 stderr 管道有关。
我已经尝试从管道中冲洗和读取 (p.stdout.flush())
我也尝试过使用不同的 Popen 参数,但可能遗漏了一些东西。只是想我会在这里保持简单。
我在 Debian 服务器上运行它。
我错过了什么吗?
编辑:
似乎只有在终止正在进行的 ffmpeg 进程时才会出现这种情况。如果ffmpeg进程在10秒前正常退出,完全没有问题。
我尝试执行几个不同的命令,这些命令需要超过 10 秒,一个打印输出,一个不打印输出,还有一个 ffmpeg 命令来检查文件的完整性。
args = ['sleep', '12s'] # Works fine
args = ['ls', '-R', '/var'] # Works fine, prints lots for a long time
args = ['ffmpeg', '-v', '1', '-i', 'large_file.mov','-f', 'null', '-'] # Breaks cli output
我相信 ffmpeg 使用 \r 打印并在 strerr 管道上打印所有内容。这可能是原因吗?任何想法如何解决它?
【问题讨论】:
【参考方案1】:嗯。你的代码在我的 Ubuntu 服务器上运行良好。
(我想这是 Debian 的近亲或兄弟)
我又添加了几行代码,以便测试您的代码。
import os
import signal
from subprocess import Popen, PIPE
class Alarm(Exception):
pass
def alarm_handler(signum, frame):
raise Alarm
def pexec(args):
p = Popen(args, stdout=PIPE, stderr=PIPE)
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(1)
stderr = ''
try:
stdout, stderr = p.communicate()
signal.alarm(0)
except Alarm:
print "Done!"
try:
os.kill(p.pid, signal.SIGKILL)
except:
pass
return (stdout, stderr)
args = ('find', '/', '-name','*')
stdout = pexec(args)
print "----------------------result--------------------------"
print stdout
print "----------------------result--------------------------"
像魅力一样工作。
如果这段代码在你的服务器上运行,我想问题实际上出在
您尝试检索数据的命令行应用程序。
【讨论】:
谢谢瑞恩,你是对的,它工作正常。似乎只有在杀死正在进行的 ffmpeg 进程时才会出现这种情况。请查看我的编辑。【参考方案2】:我也有同样的问题。我无法让正在运行的 FFmpeg 从 python 子进程正常终止,所以我使用<process>.kill()
。但是我认为这意味着 FFmpeg 无法正确恢复 tty 的模式(如此处所述:https://askubuntu.com/a/172747)
您可以通过在 bash 提示符下运行 reset
来恢复您的 shell,但这会清除屏幕,因此您在继续工作时看不到脚本的输出。
最好运行stty echo
,它会为您的 shell 会话重新打开回显。
你甚至可以在你 nuked FFmpeg 之后在你的脚本中运行它。我在做:
ffmpeg_popen.kill()
ffmpeg_popen.wait()
subprocess.call(["stty", "echo"])
这适用于我在 Ubuntu 上使用 bash 作为我的 shell。 YMMV,但我希望它有所帮助。它闻起来很老套,但这是我找到的最佳解决方案。
【讨论】:
【参考方案3】:我在使用 ffmpeg 时遇到了类似的问题。似乎如果使用 Popen.kill() 杀死 ffmpeg,它不会正确关闭并且不会在您的终端上恢复回显。
我们可以使用到标准输入的管道来解决这个问题,并像在 cli 会话中一样编写 q 来关闭 ffmpeg:
p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
p.stdin.write(b"q")
为了避免死锁,最好使用 Popen.communicate。以下也将起作用:
p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
p.communicate(b'q')
但似乎甚至以下工作:
p = Popen(args, stdin=PIPE stdout=PIPE, stderr=PIPE)
p.kill()
如果它有输入管道,我不确定是什么导致这个 ffmpeg 干净地关闭。也许它首先与导致此错误的原因有关?
【讨论】:
以上是关于杀死 python ffmpeg 子进程会破坏 cli 输出的主要内容,如果未能解决你的问题,请参考以下文章