在 Python 子进程中使用 Vim 编辑临时文件未在 Mac OS 上按预期工作
Editing temporary file with Vim in Python subprocess not working as expected on Mac OS
我最初的目标是通过命令行文本编辑器从 Python 脚本中获取用户输入。更具体地说,我的计划是创建一个临时文件并用一些预先编写的文本填充它,用文本编辑器打开文件并允许用户修改文件内容,在用户退出后从文件中读取数据editor,最后全部结束后删除文件
我似乎找到了一种对我有用的方法,但在此过程中我尝试了几种无效的方法,我想确切地了解原因。
考虑以下 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)
到目前为止,我已经在两种不同的环境中尝试 运行ning 这个脚本:macOS 计算机(运行ning macOS 10.12)和 Debian 计算机(运行ning 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 和 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)
注意调用 NamedTemporaryFile
中的 delete=False
,这确保文件在我们第一次关闭时不会被删除(我们必须使用 [=14= 手动删除它) ] 稍后)。
我认为这里发生的事情是 vim
没有编辑您的文件 in-place,它正在写入交换文件。当您保存并退出时,vim
会用编辑后的文件替换原始文件,让您的文件句柄指向旧的、未编辑的文件。有一些方法可以防止 vim
使用交换文件(参见 here),但我不推荐它们。请记住在 vim
完成任务后更新您的文件句柄。
我最初的目标是通过命令行文本编辑器从 Python 脚本中获取用户输入。更具体地说,我的计划是创建一个临时文件并用一些预先编写的文本填充它,用文本编辑器打开文件并允许用户修改文件内容,在用户退出后从文件中读取数据editor,最后全部结束后删除文件
我似乎找到了一种对我有用的方法,但在此过程中我尝试了几种无效的方法,我想确切地了解原因。
考虑以下 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)
到目前为止,我已经在两种不同的环境中尝试 运行ning 这个脚本:macOS 计算机(运行ning macOS 10.12)和 Debian 计算机(运行ning 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 和 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)
注意调用 NamedTemporaryFile
中的 delete=False
,这确保文件在我们第一次关闭时不会被删除(我们必须使用 [=14= 手动删除它) ] 稍后)。
我认为这里发生的事情是 vim
没有编辑您的文件 in-place,它正在写入交换文件。当您保存并退出时,vim
会用编辑后的文件替换原始文件,让您的文件句柄指向旧的、未编辑的文件。有一些方法可以防止 vim
使用交换文件(参见 here),但我不推荐它们。请记住在 vim
完成任务后更新您的文件句柄。