2017-09-02 9 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) 

私がこれまでに2つの異なる環境でこのスクリプトを実行しようとしました: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とtempfile PythonモジュールがmacOS上でどのようにやりとりするかと何らかの理由で失敗しているようです。何が起きてる?

答えて

0

これは、vimを呼び出す前に2番目のスクリプトがファイルハンドルを閉じてから、新しいファイルを開き、最初のスクリプトでは開きません。 tempfileモジュール自体とは何の関係もありません。このコードは期待通りに動作します:ファイルは、我々はそれを最初に閉じると削除されないことを保証NamedTemporaryFileへの呼び出しでdelete=False

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) 

注意は、(我々は後でos.unlinkを手動で削除する必要があります)。

ここで起こっていることは、vimがファイルをインプレースで編集していないことです。スワップファイルに書き込んでいます。保存して終了すると、vimは元のファイルを編集済みのものに置き換え、ファイルハンドルは編集されていない古いものを指します。vimがスワップファイルを使用しないようにする方法があります(例:here参照)が、私はそれらをお勧めしません。 vimが業務を終えた後でファイルハンドルを更新することを忘れないでください。

関連する問題