Emacs shell-mode 中的 Python 打开 stty echo 并中断 C-d

Posted

技术标签:

【中文标题】Emacs shell-mode 中的 Python 打开 stty echo 并中断 C-d【英文标题】:Python in Emacs shell-mode turns on stty echo and breaks C-d 【发布时间】:2013-10-15 06:42:19 【问题描述】:

当我在 Emacs shell 缓冲区(M-x shell)中运行交互式 Python 时,它对 TTY 做了两件令人惊讶的事情。首先,它打开输入回显,它在 Python 退出后仍然存在,直到我执行 stty -echo。其次,它不接受 C-d(或 C-q C-d,即 ^D)作为 EOF:我必须键入 quit() 才能离开 Python。我怎样才能阻止这两种行为?

我知道我可以运行 python-shell,但我不想:我在 shell 中闲逛,我想做五行 Python,然后 C-d 出来。所以“运行 python-shell”不是我问题的答案。

在终端窗口中运行的 Python 很好:^D 继续工作,并且 echo 没有改变。

Python 2.7.5、GNU Emacs 24.3.1、OS X 10.8.5

已编辑以从 shell 缓冲区添加此 sn-p:

bash-3.2$ echo foo 
foo                     # no echo.
bash-3.2$ cat
foo                     # I typed this.
foo                     # cat returned it; no additional echo.
bash-3.2$ python
Python 2.7.5 (default, May 19 2013, 13:26:46) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>                   # C-d has no effect. C-q C-d has no effect.
                      # not sure where this blank link has come from.
>>> quit()              # I have to type this to get out of Python
quit()                  # note that it is echoed, like anything I now type.
bash-3.2$ echo foo
echo foo                # now I am getting my input echoed.
foo
bash-3.2$ cat
cat                     # echo of the 'cat' command.
foo                     # my input
foo                     # echo of my input.
foo                     # cat's output.
bash-3.2$ stty -echo    # turn echo back off.
stty -echo
bash-3.2$ echo foo
foo                     # and it's off.
bash-3.2$ 

【问题讨论】:

无法在 openSuse 上重现。也许是 OSX 问题?顺便说一句,调用 Python 的命令是什么? 为了调用 python,我在 shell 提示符下输入了 python。 无法重现(我使用 Linux)...sys.displayhook("foo") 的输出是否回显?你在 PYTHONSTARTUP 中有什么吗? sys.displayhook('foo') 的输出只出现一次(如我所料)。 PYTHONSTARTUP 中没有任何内容。 Gareth Rees 的回答如下,非常完整和明确。 【参考方案1】:

0。总结

如果您通过 Macports 安装 Python,请安装 py27-gnureadline 端口(或 py37-gnureadline,或任何您的版本),问题就解决了。

1。复制

我可以重现这个(GNU Emacs 23.4.1;OS X 10.8.5;Python 3.3.2)。这是一个新的emacs -Q 中的会话,显示了问题:

$ stty -a > stty-before
$ python3.3
Python 3.3.2 (default, May 21 2013, 11:50:47) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
quit()
$ stty -a > stty-after
stty -a > stty-after
bash-3.2$ diff stty-before stty-after
diff stty-before stty-after
2c2
< lflags: icanon isig iexten -echo echoe -echok echoke -echonl echoctl
---
> lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl
7c7
< oflags: opost -onlcr -oxtabs -onocr -onlret
---
> oflags: opost onlcr -oxtabs -onocr -onlret
11,13c11,13
<   eol2 = <undef>; erase = <undef>; intr = ^C; kill = <undef>;
<   lnext = ^V; min = 1; quit = ^\; reprint = ^R; start = ^Q;
<   status = ^T; stop = ^S; susp = ^Z; time = 0; werase = ^W;
---
>   eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;
>   min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T;
>   stop = ^S; susp = ^Z; time = 0; werase = ^W;

因此您可以看到 Python 打开了 ECHOONLCR 标志。为什么这样做?为什么它只在 OS X 上这样做?

2。什么叫tcsetattr

我在 GDB 下运行 Python 并在 tcsetattr 上设置断点以查看调用它的内容。以下是回溯的相关部分:

#0  0x00007fff898e7e63 in tcsetattr ()
#1  0x00000001007cbe96 in tty_init ()
#2  0x00000001007c19cf in el_init ()
#3  0x00000001007d1bb7 in rl_initialize ()
#4  0x00000001003f10ea in PyInit_readline ()
#0  0x00007fff898e7e63 in tcsetattr ()
#1  0x00000001007cc812 in tty_rawmode ()
#2  0x00000001007c610f in read_prepare ()
#3  0x00000001007c203d in el_wset ()
#4  0x00000001007d554d in el_set ()
#5  0x00000001003f128a in call_readline ()

PyInit_readlinecall_readlinereadline.c 中的函数,但是从回溯可以看出,这不是这里调用的真正的readline 库,而是最兼容的editline 库。 OS X 附带 BSD 许可的编辑行而不是 GPL 许可的读取行,因此这可以解释为什么 OS X 上的行为与其他 Unix 不同。

3。与 Python 无关

其他交互式解释器也会发生同样的情况。我发现 Lua、Ruby 和 Sqlite3 命令行解释器在 Emacs 中运行时也会打开终端回显。所以它似乎是编辑线库的某种“功能”。让我们通过运行这个短程序来测试这个理论:

#include <readline/readline.h>

int main() 
    char *line = readline("> ");
    return 0;

果然,当用

编译时
$ clang rl.c -lreadline

这个程序在 Emacs 中运行时也会打开终端回显。但是当用

编译时
$ clang rl.c -L/opt/local/lib -lreadline

这导致它与由 MacPorts 安装的真实 (GNU) readline 库链接,它按预期工作(未打开 echo)。

4。错误和解决方法

所以这看起来像是编辑线库中的一个错误。让我们使用DYLD_PRINT_LIBRARIES 检查这确实是库的系统版本,而不是(比如说)MacPorts 版本:

$ export DYLD_PRINT_LIBRARIES=1
$ /usr/bin/python
dyld: loaded: /usr/bin/python
dyld: loaded: /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
[... many lines omitted ...]
dyld: loaded: /usr/lib/libstdc++.6.dylib
Python 2.6.7 (r267:88850, Oct 11 2012, 20:15:00) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
dyld: loaded: /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-dynload/readline.so
dyld: loaded: /usr/lib/libedit.3.dylib
dyld: loaded: /usr/lib/libncurses.5.4.dylib
>>> 

我已将此问题作为错误 15184759 报告给 Apple。我了解 Apple 使用报告问题的人数作为问题严重性的指标,因此如果您希望解决问题,请自行报告问题。

现在,我相信这在最近升级到 OS X 时出现了问题,因此最近对 libedit 的更改似乎引入了该错误。以下是 MacPorts 安装的 libedit 版本:

$ port installed libedit
The following ports are currently installed:
  libedit @20110802-3.0_0
  libedit @20120601-3.0_0
  libedit @20121213-3.0_0 (active)

如果我回到 2012 年 6 月的版本:

$ sudo port activate libedit@20120601-3.0_0
--->  Computing dependencies for libedit
--->  Deactivating libedit @20121213-3.0_0
--->  Cleaning libedit
--->  Activating libedit @20120601-3.0_0
--->  Cleaning libedit

然后这解决了我测试的所有交互式解释器(Python、Ruby、Sqlite3)的 MacPorts 版本中的两个问题(终端 ECHO 标志和损坏的 C-d)。

因此,如果您正在寻找解决问题的方法,就是这样:使用 MacPorts 恢复到 libedit 崩溃之前的版本,并将 /opt/local/bin 放在您的 PATH 上,这样当您键入 python您将获得 Python 的 MacPorts 安装,而不是系统安装。 (可能你已经这样做了,因为我看到你的 Python 是 2.7.5 而系统版本是 2.6.7。)

5。向上游报告

我从上游downloaded the latest version of libedit 看看那里的问题是否已解决。但事实并非如此。所以我联系了 Jess Thrysoee 并报告了这个错误。

6。更新

截至 2018 年 12 月,该问题尚未在 libedit 中得到修复。但是,如果您使用的是 Macports,则有一种解决方法(请参阅 issue #48807):您可以安装 pyXX-gnureadline 端口(其中 XX 是您的 Python 版本,例如 py27-gnureadline 或 py35-gnureadline),它将 Python 与GNU readline 库而不是 libedit。现在终端设置不变:

$ sudo port install py37-gnureadline
[...]
$ stty -a > stty-before
$ python3.7
Python 3.7.1 (default, Oct 21 2018, 09:01:26) 
[Clang 10.0.0 (clang-1000.11.45.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()
$ stty -a > stty-after
$ diff stty-before stty-after 
$ 

【讨论】:

好的。所以我想我可以通过将 Python 包装在脚本中来解决烦人的回声问题。我可以对 C-d 行为做些什么吗?为什么这不起作用? @NickBarnes:查看修改后的答案,其中包括解决方法。 这一切都很好,谢谢 Gareth。我已经报告了 Apple 错误 15186465。 我对旧版本的 libedit 和 mac 端口也有同样的看法。相反,我从thrysoee.dk/editline 编译了源代码,移动了 Apple 文件(添加了 .bak,以防万一),并将原始文件名的符号链接指向 /usr/local/lib 中的新文件名……它似乎循规蹈矩。 如果您在 OS X 10.5.8 上,在任何情况下都不要替换 libedit.2.dylib。如果你这样做,你会发现无限递归重启的纯粹地狱。幸运的是,SystemRescueCD 使用 hfsplusutils 帮助我并强制重写安装。即便如此,过去 2 天还是很糟糕......【参考方案2】:

使用 readline 变体从 MacPorts 安装 Python 将解决这个问题和 libedit 中的其他错误。

$ sudo port install python27 +readline

Python 2.7.11 错误地将提示与输出交错并在退出时使 tty 处于疯狂状态时遇到问题。配置 Python 使用 readline 解决了这些问题。

【讨论】:

以上是关于Emacs shell-mode 中的 Python 打开 stty echo 并中断 C-d的主要内容,如果未能解决你的问题,请参考以下文章

在emacs 里使用gdb

python 用于开发的sanic入门脚本(支持auo-reload,shell-mode)

EmacsMacPort (Emacs.app) 不加载我自己的,MacOS 中的 ~/.emacs

如何修复 emacs 24 中的 javascript 模式更改?

更改 Emacs 中的默认文件夹

Windows 7 中的主目录和 .emacs 文件