I am dealing with a Python script which does, after some preparation work, launch ssh
. My script is actually a small CLI tool. On Unix-like systems, at the end of its life, the Python script replaces itself with the ssh
client, so the user can now interact with ssh
directly (i.e. run arbitrary commands on the remote machine etc):
os.execvpe('ssh', ['ssh', '-o', 'foo', 'user@host'], os.environ)
Positive surprise & side-note in case you are wondering: Windows 10 actually has a native version of OpenSSH now built-in, so there is a ssh
command on this platform.
os.execvpe
is present in the Python standard library on Windows, but it does not replace the original (Python) process. The situation is ... somewhat complicated: 1, 2, 3. Bottom line: Windows does not implement the corresponding POSIX semantics for replacing a running process.
The common wisdom is to use subprocess.Popen
instead, ok, effectively creating a child process. I can launch the child so that the parent keeps running OR I can launch the child while the parent dies (I think that Windows does support the latter just like Unix-like systems). Either way, the user can not interact with the child in the command line.
Assuming that I keep the parent alive, I now have to write a ton of code to pass user I/O to/from the child through the parent, like so for instance. The latter involves managing streams and even threads, depending on how well it is supposed to behave - a lot of places for potential issues and breakages down the road. I do not like to do this (if I can avoid it).
How can I efficiently replace os.execvpe
on Windows in the described scenario?
EDIT (1): Bits and pieces, which may be relevant ...
- Handle Inheritance I
- Handle Inheritance II
- STARTUPINFO in Windows
- STARTUPINFO in Windows - for Python
I guess it depends on figuring out how to correctly configure a STARTUPINFO
object before passing it into Popen
. A command line can in fact be inherited in Windows.
EDIT (2): A partial solution via pywin32
- ssh
opens into a second, new cmd
window and can be interacted with. The original shell with Python remains open, Python itself quits:
from win32.Demos.winprocess import Process
from shlex import join
Process(join(['ssh', '-o', 'foo', 'user@host']))