我正在尝试实现raw_input()的替换,它将使用可配置的文本编辑器(如vim)作为与用户的接口。
理想的工作流程如下:
如果您熟悉git,则可以使用git commit,这是通过core.editor配置编辑器的经验。其他实用程序crontab -e也可以这样做。
git commit
crontab -e
最终,我希望my_raw_input()函数也可以使用带有默认输入内容的可选字符串,然后用户可以对其进行编辑。
-
:w
这可能吗?
到目前为止,很好的答案。我还发现了做相同事情的商业代码。我还想出了一个可以通过查看crontab代码来工作的示例,但是与某些响应相比,它看起来像是不必要的复杂。
#!/usr/bin/python import os import tempfile def raw_input_editor(default=None, editor=None): ''' like the built-in raw_input(), except that it uses a visual text editor for ease of editing. Unline raw_input() it can also take a default value. ''' editor = editor or get_editor() with tempfile.NamedTemporaryFile(mode='r+') as tmpfile: if default: tmpfile.write(default) tmpfile.flush() child_pid = os.fork() is_child = child_pid == 0 if is_child: os.execvp(editor, [editor, tmpfile.name]) else: os.waitpid(child_pid, 0) tmpfile.seek(0) return tmpfile.read().strip() def get_editor(): return (os.environ.get('VISUAL') or os.environ.get('EDITOR') or 'vi') if __name__ == "__main__": print raw_input_editor('this is a test')
您将数据写入一个临时文件,然后在编辑器返回时读取它。如果运行,git commit您会注意到git在做同样的事情。
只要子进程具有stdin并stdout连接到终端的交互过程,就没有多余的步骤来交互式地启动程序。
stdin
stdout
与编辑器打交道有一个陷阱- 他们中的许多人将通过在同一目录中写入临时文件并将其移至旧文件上来保存文件。这使保存操作完全原子化(忽略电源可能会耗尽),但意味着我们必须在编辑器运行后重新打开临时文件,因为旧文件句柄将指向不再属于该文件的文件。文件系统(但仍在磁盘上)。
这个陷阱意味着我们不能使用TemporaryFile或NamedTemporaryFile,我们必须使用较低级别的工具,以便我们可以关闭文件描述符并重新打开文件而不删除它。
TemporaryFile
NamedTemporaryFile
import tempfile import subprocess import os def edit(data): fdes = -1 path = None fp = None try: fdes, path = tempfile.mkstemp(suffix='.txt', text=True) fp = os.fdopen(fdes, 'w+') fdes = -1 fp.write(data) fp.close() fp = None editor = (os.environ.get('VISUAL') or os.environ.get('EDITOR') or 'nano') subprocess.check_call([editor, path]) fp = open(path, 'r') return fp.read() finally: if fp is not None: fp.close() elif fdes >= 0: os.close(fdes) if path is not None: try: os.unlink(path) except OSError: pass text = edit('Hello, World!') print(text)
Git示例代码非常复杂,因为它没有使用像Python的subprocess模块这样的高级库。如果您阅读了subprocess模块源代码,则其中的很大一部分将看起来像链接的Git源代码(用Python代替C编写的除外)。
subprocess