4

一个 OSX 用户提交了一个错误,该错误CTRL+Y导致 python 终端应用程序被挂起,通过dsusp导致当 Python 程序尝试在标准输入上读取时发送 SIGTSTP。下面的代码解决了这个问题:(上下文

import sys
import termios
if sys.platform == 'darwin':
    attrs = termios.tcgetattr(0)
    VDSUSP = termios.VSUSP + 1
    attrs[-1][VDSUSP] = 0
    termios.tcsetattr(0, termios.TCSANOW, attrs)
  • 如何检测到此功能(dsusp)?有没有我可以基于os.uname()或类似使用的启发式方法?
  • termios.VDSUSP不存在,即使在拥有它的系统上也是如此。有没有它失踪的原因?
  • 这种关闭它的行为有多普遍?使用 readline 的程序似乎在 OSX 上忽略了CTRL+ Y,所以它至少相当普遍。我很久以前添加stty dsusp undef到我的 .bashrc 中,所以没有注意到它。

要查看此挂起行为,请在 OSX 或其他具有此功能的设备上运行cat并输入CTRL+ 。Y Return

$ cat
^Y

[1]+ Stopped             cat
$ fg
cat
cat: stdin: Resource temporarily unavailable
4

1 回答 1

3

我无法检查此行为的实际行为,因为我没有任何具有具有该DSUSP行为的操作系统的计算机。然而,在调查这个问题时,我在 Python bug tracker 中遇到了问题 7695。似乎VDSUSP只能termios从 3.4 开始使用。


Glibc 文档,说

宏:intVDSUSP

这是DSUSP特殊控制字符数组中字符的下标。termios.c_cc[VDSUSP]持有角色本身。

仅当DSUSP实现支持作业控制时才识别(挂起)字符(请参阅作业控制)。它发送一个SIGTSTP信号,就像SUSP字符一样,但不是马上——只有当程序试图将它作为输入读取时。并非所有具有作业控制的系统都支持 DSUSP;仅与 BSD 兼容的系统(包括 GNU/Hurd 系统)


因此,我建议您检查 in 的存在VDSUSP-termios它将3.4 开始存在;否则回退到

if any(i in sys.platform for i in ['bsd', 'darwin']):

哪个应该匹配 BSD 和你的 OS X;Hurd 是一个很大的问号,因为我无法确定您的修复是否正确(我想它在所有 BSD 版本上都可以类似地工作)。

更简单的是这样做:

import subprocess
import time
from distutils.spawn import find_executable

def exec_cmd(*args):
    p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, _ = p.communicate()
    return stdout

if find_executable('stty'):
    modesave = exec_cmd('stty', '-g').strip()
    exec_cmd('stty', 'dsusp', 'undef')
    print("disabled ctrl-y")
    time.sleep(2)
    print("enabled ctrl-y")
    exec_cmd('stty', modesave)
    time.sleep(2)
    print("exiting")

至少这不会炸毁我的 Linux,并且stty命令本身-g等都是 POSIX 标准。

于 2015-03-23T07:18:18.787 回答