在 Python 中禁用 DSUSP

Disable DSUSP in Python

一个 OSX 用户 submitted a bug that CTRL+Y causes a python terminal application to be suspended, via dsusp causing SIGTSTP to be sent when the Python program tried to read on stdin. The code below to solves the problem: (context)

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)

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

$ cat
^Y

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

我无法检查此行为的实际行为,因为我没有任何计算机的操作系统会出现 DSUSP 行为。 然而,在调查这个问题时,我遇到了 issue 7695 in Python bug trackerVDSUSP 似乎只在 3.4 之后的 termios 中可用。


Glibc documentation,也就是说

Macro: int VDSUSP

This is the subscript for the DSUSP character in the special control character array. termios.c_cc[VDSUSP] holds the character itself.

The DSUSP (suspend) character is recognized only if the implementation supports job control (see Job Control). It sends a SIGTSTP signal, like the SUSP character, but not right away—only when the program tries to read it as input. Not all systems with job control support DSUSP; only BSD-compatible systems (including GNU/Hurd systems).


因此,我建议您检查 termios 中是否存在 VDSUSP - 它 从 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 标准。