使用Python子进程中的Vim编辑临时文件在Mac OS上无法正常工作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Python子进程中的Vim编辑临时文件在Mac OS上无法正常工作相关的知识,希望对你有一定的参考价值。

我最初的目标是通过Python脚本中的命令行文本编辑器获取用户输入。更具体地说,我的计划是创建一个临时文件并用一些预先写好的文本填充它,用文本编辑器打开文件并允许用户修改文件内容,在用户退出后从文件中读取数据编辑器,然后最后删除文件后全部删除。

我似乎已经找到了一种方法来做到这一点,这对我有用,但一路上我尝试了几种不起作用的方法,我想知道究竟为什么。

考虑以下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!”在屏幕上显示 - 就像在编辑文件之前正在读取文件一样。

但是,如果使用EDITOR=nano在我的Mac上运行脚本,那么一切似乎都按预期工作。

我使用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和tempfile Python模块如何在macOS上进行交互而失败。这里发生了什么?

答案

发生这种情况是因为你的第二个脚本在调用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=False调用中的NamedTemporaryFile,它确保在我们第一次关闭文件时不删除文件(我们必须稍后用os.unlink手动删除它)。

我想这里发生的是vim没有就地编辑你的文件,它正在写一个交换文件。保存并退出时,vim将原始文件替换为已编辑的文件,使文件句柄指向旧的未编辑文件。有办法阻止vim使用交换文件(参见,例如here),但我不推荐它们。请记住在vim完成业务后更新文件句柄。

以上是关于使用Python子进程中的Vim编辑临时文件在Mac OS上无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

ubuntu 配置vim编辑器

Python 子进程 readlines() 挂起

iOS开发之--解决 swap file “*.swp”already exists!问题

vim 永久临时显示行号

使用python中的子进程库验证文件或文件夹的存在

git忽略vim临时文件