【问题标题】:Terminal text becomes invisible after terminating subprocess终止子进程后终端文本变得不可见
【发布时间】:2011-09-23 05:10:10
【问题描述】:

在终止ffmpeg 子进程后,终端变得一团糟——输入的字符是不可见的!输入仍然有效,可以执行命令,但键盘输入不会回显到终端。

发出 shell 命令 reset 使一切恢复正常(或在 ipython 中 !reset),因此解决此问题的方法是在脚本中调用 os.system('reset')

我尝试过的其他事情:在产生子进程之前import curses; curses.initscr() 和在终止之后curses.endwin(),这有点工作但破坏了其他东西。另一个可能相关的问题是,在生成子进程后,交互式终端变得迟钝,有时无法捕获键入的字符。

生成进程的代码如下所示:

with open('/tmp/stdout.log', 'w') as o:
    with open('/tmp/stderr.log', 'w') as e:
        proc = subprocess.Popen([args], stdout=o, stderr=e)

然后停止它:

proc.terminate()
proc.communicate()

这里可能出了什么问题?

【问题讨论】:

  • 我猜这和stdout=o, stderr=e有关
  • django runserver在重新加载时也存在同样的问题。
  • 我已将 stdout 和 stderr 重定向到 os.devnull 并且问题仍然存在
  • 我认为您重定向了输出,并且在进程终止后它不会返回。
  • 某些东西会改变终端设置并且不会恢复它们。如果是您的代码;你可以use a context manager to restore the terminal whether an error occurs or not。如果它是子进程(ffmpeg),那么您可以尝试更温和地关闭它(如您的回答所尝试的那样),例如,proc = Popen(..., stdin=PIPE); ...; proc.stdin.write("q")/.close()

标签: python terminal ffmpeg subprocess


【解决方案1】:

更改脚本以便不使用proc.terminate()。您可以更礼貌地停止ffmpeg 子进程

  proc.send_signal(signal.SIGINT)
  proc.wait()

这让 ffmpeg 有机会编写恢复终端所需的任何转义序列。


编辑: 稍后发现 - 使 ffmpegPopen 一起表现更好的另一个技巧是在 stdin 句柄中为其提供 subprocess.PIPEopen(os.devnull)。否则,它似乎会尝试从父母的标准输入中获取输入,这可能会导致奇怪的终端行为。正在运行的 ffmpeg 进程正在监听“?”和标准输入上的“q”输入。

【讨论】:

  • 我正在使用 sudo 运行一个子进程,所以我没有发送 SIGINT 的权限。对我来说,这样做就足够了:proc.stdin.close; proc.wait()
【解决方案2】:

this answer 中所述,ffmpeg 需要来自标准输入的数据。您可以使用 -nostdin 标志运行 ffmpeg,它会阻止您的终端隐藏击键。

【讨论】:

    【解决方案3】:

    您是否与子进程通信?在那种情况下,我会使用 pexpect 这使得这种类型的设置非常简单,也许你必须等待命令完成?即

     p = subprocess.Popen(argv, stdout=o, stderr=e)
     p.wait()
     if p.returncode != 0:
          print("problems")
    

    这就是我在不久前写的 dvd2h264 脚本上使用的,从来没有遇到过任何问题,但我不会将 stdin/stderr 重定向到 tmpfiles..

    【讨论】:

    • 没有真正的交互式通信 - 我正在编码从采集卡输入的实时流,当脚本接收到 SIGINT(来自键盘或另一个脚本)。我也尝试过使用 proc.send_signal(signal.SIGINT) ,并在检查 proc.returncode 之前等待半秒 .. 如果它仍然是 None 然后我用 terminate() 杀死它,我认为它使用 SIGTERM
    • 好的,您能否提取失败的代码,即制作一个我可以尝试的hallo fail 示例?终端失败的原因一定是转义序列被写入标准输出,但为了看看会发生什么,产生错误的微小代码片段会有所帮助。
    • 谢谢,我见过你可以使用转义序列在彩色文本中书写的案例,所以你给了我一些尝试的想法——也许我需要“取消转义”回到纯文本。不幸的是,我无法为您提供始终失败的示例,因为这似乎是一个间歇性问题,您可能需要相同的采集卡来重现它
    • 嗨,是的,这都是转义序列,重置终端可以通过这样的方式完成,sys.stdout.write(curses.tigetstr('sgr0'))
    【解决方案4】:

    os.system('stty sane') 为我工作。它重置设置,使回声不可见。

    【讨论】:

      猜你喜欢
      • 2019-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 2016-04-12
      • 1970-01-01
      • 2014-10-25
      相关资源
      最近更新 更多