如何在Python sh模块中不屏蔽交互式vim命令?

4 投票
1 回答
999 浏览
提问于 2025-04-20 08:56
import sh
sh.vim("lalala")

在我的控制台里没有显示vim编辑器。设置 _bg=False 这个参数没有任何变化(因为这已经是默认值了)

如果我使用 subprocess 模块,就能正常工作:

import subprocess
subprocess.call(["vim", "lalala"])

1 个回答

5

问题在于,vim 期望它的输入是一个 TTY(终端),但通过 sh 创建的管道并不是 TTY,而是一个管道。

解决办法是不要试图用管道来拦截 vim 的标准输入输出。因为用管道拦截标准输入输出正是 sh 的主要功能,所以与其想办法去对抗,不如干脆不使用它。你可以直接使用标准库中的 subprocess 模块,只有在你特别要求的情况下,它才会拦截标准输入输出:

subprocess.check_call(['vim', 'lalala'])

不过,注意一下 sh 文档中的 TTYs 部分:

一些应用程序的行为会根据它们的标准文件描述符是否连接到 TTY 而有所不同。例如,当标准输出(STDOUT)没有连接到 TTY 时,git 会禁用一些面向人类的功能,比如彩色输出和分页输出。其他程序可能会在标准输入(STDIN)没有连接到 TTY 时禁用交互输入。还有一些程序,比如 SSH(不带 -n 选项),期望它们的输入来自 TTY/终端。

默认情况下,sh 会为标准输出模拟一个 TTY,但标准输入则不会。你可以通过传入额外的特殊关键字参数来改变这个默认行为……

所以,如果你传入 _tty_in=True,那么 vim 的输入就会是一个模拟的 TTY,而不是管道。

但这仍然不会有什么太大帮助。它会让 vim 运行,但它会使用 sh 为输入和输出创建的假 TTY,这我想并不是你想要的。(如果你想发送控制序列并捕获和处理它返回的控制序列,直接用脚本写 ed,或者更好的是 sed,会简单得多……)


那么,为什么你没有收到任何错误信息或其他正常的行为呢?

这其实是因为 vim 的原因。如果你用 emacs 或任何使用 curses 的应用程序,或者其他许多 TTY 应用程序尝试同样的事情,它们会在错误输出(stderr)中写入错误信息,并以 1 退出,这样你就会看到类似这样的信息:

ErrorReturnCode_1:

  RAN: '/usr/bin/emacs -nw'

  STDOUT:


  STDERR:
emacs: standard input is not a tty

撰写回答