DiputsMonro
DiputsMonro

Reputation: 43

Running vi from Python script

I'm trying to open a file with vanilla vi (/usr/bin/vi on Solaris 10) from a Python (2.6.4) script, and nothing I do seems to be working. I want to have the script put some data in a temporary file, then open that file in vi for the user to edit. Ideally the script would block on the call to vi and continue executing when the user is finished, but I could settle for solutions transforming the script process into the vi process (via exec or something).

I've tried the following, but for each of them vi prints the first page of the file to the screen and then exits with a "Input read error":

os.execlp('vi', 'vi', filename)

os.system('vi' + ' ' + filename)

subprocess.call('vi' + ' ' + filename, shell=True)

For context, here is the code in its entirety:

#!/usr/bin/python

import sys
import os
import subprocess

fname = "." + str(os.getpid()) + ".pvi.tmp"
f = open(fname, 'w')

f.write("## Remember to save this to a new file if you want to keep it!\n")

for line in sys.stdin:
    f.write(line + "\n")

f.close()

# These all give the error "Input read error"
#os.execlp('vi', 'vi', fname)
#os.system('vi' + ' ' + fname)
#subprocess.call('vi' + ' ' + fname, shell=True)

os.unlink(fname)

I'm basically trying to emulate piping processes into vi, which my version doesn't support (vi - doesn't work). I would pipe them to this script which would then write the output to a temporary file and open it in vi.

Any help would be much appreciated!

Upvotes: 3

Views: 2562

Answers (3)

Mark Reed
Mark Reed

Reputation: 95315

The problem is that the standard input to vi is inherited from your script, which means it's attached to the pipe and not the terminal. Try this:

os.system('vi' + ' "' + fname + '" </dev/tty >/dev/tty 2>&1')

This is dangerous if fname comes from user input, since it could include embedded shell metacharacters and cause arbitrary commands to get executed. But in your code that appears not to be the case; you're constructing the value deterministically.

The alternative would be to use one of the exec calls to bypass the shell, but then you would have to also do the I/O redirection within the Python, and that gets a bit unwieldy. Whether or not it's worth the effort would depend on the risk exposure of your application. But again, this doesn't seem to be a concern in your particular case.

Upvotes: 3

Robᵩ
Robᵩ

Reputation: 168706

Your vi program's standard input is not connected to a terminal. One solution is to launch a new terminal:

os.system('xterm -e vi ' + fname)

Upvotes: 0

Adam
Adam

Reputation: 17369

Your system call works for me on OSX:

os.system('vi' + ' ' + fname)

As it should. One consideration in this case is what happens to stdin. If you run this without redirection it works. But if you redirect stdin, for example with python scripty.py < input.txt then VI complains. It gives me Vim: Warning: Input is not from a terminal.

Upvotes: 0

Related Questions