2017-09-02 109 views
2

我最初的目标是通过Python脚本中的命令行文本编辑器获取用户输入。更具体地说,我的计划是创建一个临时文件并使用一些预先写好的文本填充它,使用文本编辑器打开文件,并允许用户修改文件内容,在用户退出后从文件中读取数据编辑器,然后在完成后最后删除文件。使用Python子进程中的Vim编辑临时文件在Mac OS上无法按预期工作

我似乎找到了一种方法可以做到这一点,但我一直在尝试一些方法,但没有奏效,我想明白为什么。

考虑以下Python脚本(从this post拍摄脚本的稍作修改的版本):

#!/usr/bin/env python2 
# -*- encoding: ascii -*- 
"""callvim.py 

Demonstrates calling a text-editor (e.g. Vim) from within a Python script, 
including passing input to the editor and reading output from the editor. 
""" 

import tempfile 
import os 
from subprocess import call 

# Get the text editor from the shell, otherwise default to Vim 
EDITOR = os.environ.get('EDITOR','vim') 

# Set initial input with which to populate the buffer 
initial_message = "Hello world!" 

# Open a temporary file to communicate through 
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf: 

    # Write the initial content to the file I/O buffer 
    tf.write(initial_message) 

    # Flush the I/O buffer to make sure the data is written to the file 
    tf.flush() 

    # Open the file with the text editor 
    call([EDITOR, tf.name]) 

    # Rewind the file offset to the beginning of the file 
    tf.seek(0) 

    # Read the file data into a variable 
    edited_message = tf.read() 

    # Output the data 
    print(edited_message) 

我试过至今运行在两个不同的环境中,此脚本:MacOS的计算机上(运行MacOS的10.12)和Debian计算机(运行Debian 8.8)。这两台电脑都安装了相同(小)版本的Vim(Vim 7.4)。

当我在我的Debian 8(Jessie)机器上运行EDITOR=vim这个脚本时,它按预期工作。我得到Vim提示和一个包含字符串“Hello world!”的缓冲区。在编辑缓冲区以包含字符串“Goodbye world!”,保存文件并退出Vim之后,我看到字符串“Goodbye world!”。打印到控制台。

当我在我的macOS 10.12(Sierra)机器上运行相同的脚本时,它似乎不起作用。相同的程序导致“Hello world!”显示在屏幕上 - 就像文件在被编辑之前正在被读取一样。

但是,如果在我的Mac上运行脚本EDITOR=nano然后再次一切似乎按预期工作。

我尝试了使用tempfile模块中不同方法(例如使用tempfile.TemporaryFile()tempfile.mkstemp())的相同结果对此脚本进行了一些更改。

现在考虑下面的替代文字:

#!/usr/bin/env python2 
# -*- encoding: ascii -*- 
"""callvim.py 

Demonstrates calling a text-editor (e.g. Vim) from within a Python script, 
including passing input to the editor and reading output from the editor. 
""" 

import subprocess 
import os 

# Create a temporary file and write some default text 
file_path = "tempfile" 
file_handle = open(file_path, "w") 
file_handle.write("Hello world!") 
file_handle.close() 

# Open the file with Vim 
subprocess.call(["vim", file_path]) 

# Rewind to the beginning of the file 
file_handle = open(file_path, 'r') 

# Read the data from the file 
data = file_handle.read() 

# Close the temporary file 
file_handle.close() 

# Delete the temporary file 
os.remove(file_path) 

# Print the data 
print(data) 

这个脚本,从而避免了使用tempfile模块,似乎这两个平台的一贯工作。

因此,看起来这个脚本可能由于某种原因而无法处理Vim和Python模块如何在macOS上进行交互。这里发生了什么?

回答

0

这是因为你的第二个脚本在调用vim之前关闭文件句柄,然后打开一个新的脚本,而第一个脚本没有。它与tempfile模块本身无关。此代码按预期工作:

import tempfile, os 
from subprocess import call 

initial_message = "Hello world!" 

tf = tempfile.NamedTemporaryFile(suffix=".tmp", delete=False) 
tf.write(initial_message) 
tf.close() 

call(['vim', tf.name]) 

tf = open(tf.name, 'r') 
edited_message = tf.read() 
tf.close() 

os.unlink(tf.name) 

print(edited_message) 

注意在呼叫中的delete=FalseNamedTemporaryFile,这保证了当我们关闭它的第一次的文件不会被删除(我们必须与os.unlink手动删除它以后)。

我想这里发生的事情是,vim不是就地编辑文件,而是写入交换文件。当您保存并退出时,vim会用编辑的文件替换原始文件,并将文件句柄指向旧的未编辑的文件。有一些方法可以防止vim使用交换文件(请参阅,例如here),但我不会推荐它们。请记住在vim完成其业务后更新文件句柄。