2017-09-02 110 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完成其業務後更新文件句柄。