我正在处理一个 Python 脚本,经过一些准备工作后,它会启动 ssh
.我的脚本实际上是一个小的 CLI 工具。在类 Unix 系统上,在其生命周期结束时,Python 脚本将自身替换为 ssh
客户端,因此用户现在可以与 ssh
进行交互直接(即在远程机器上运行任意命令等):
os.execvpe('ssh', ['ssh', '-o', 'foo', 'user@host'], os.environ)
如果您想知道的话,正面的惊喜和旁注:Windows 10 实际上现在内置了一个 native 版本的 OpenSSH,所以有一个 ssh
在这个平台上指挥。os.execvpe
存在于 Windows 上的 Python 标准库中,但它不会取代原始 (Python) 进程。情况……有点复杂:1 , 2 , 3 .底线: Windows 没有实现相应的 POSIX 语义来替换正在运行的进程。 常识是用
subprocess.Popen
相反,好的,有效地创建一个子进程。我可以启动子进程以便父进程继续运行,或者我可以在父进程死亡时启动子进程(我认为 Windows 确实像类 Unix 系统一样支持后者)。无论哪种方式,用户都无法在命令行中与 child 进行交互。假设我让父级保持事件状态,我现在必须编写大量代码来通过父级将用户 I/O 传递给/从子级传递,例如 so例如。后者涉及管理流甚至线程,这取决于它应该表现得有多好 - 很多地方可能会出现潜在问题和故障。我不喜欢这样做(如果我可以避免的话)。
如何高效更换
os.execvpe
在所描述的场景中的 Windows 上?编辑(1):点点滴滴,这可能是相关的......
我想这取决于弄清楚如何正确配置
STARTUPINFO
对象,然后将其传递给 Popen
.命令行实际上可以在 Windows 中继承。编辑 (2):通过
pywin32
的部分解决方案- ssh
打开第二个,新的cmd
窗口,可以进行交互。带有 Python 的原始 shell 保持打开状态,Python 本身退出:from win32.Demos.winprocess import Process
from shlex import join
Process(join(['ssh', '-o', 'foo', 'user@host']))
最佳答案
A 部分和不完整 解决方法如下,见 TODO评论 :
import win32api, win32process, win32con
from shlex import join
si = win32process.STARTUPINFO()
# TODO fix flags
si.dwFlags = win32con.STARTF_USESTDHANDLES ^ win32con.STARTF_USESHOWWINDOW
# inherit stdin, stdout and stderr
si.hStdInput = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE)
si.hStdOutput = win32api.GetStdHandle(win32api.STD_OUTPUT_HANDLE)
si.hStdError = win32api.GetStdHandle(win32api.STD_ERROR_HANDLE)
# TODO fix value?
si.wShowWindow = 1
# TODO set values?
# si.dwX, si.dwY = ...
# si.dwXSize, si.dwYSize = ...
# si.lpDesktop = ...
procArgs = (
None, # appName
join(['ssh', '-o', 'foo', 'user@host']), # commandLine
None, # processAttributes
None, # threadAttributes
1, # bInheritHandles TODO ?
win32process.CREATE_NEW_CONSOLE, # dwCreationFlags
None, # newEnvironment
None, # currentDirectory
si, # startupinfo
)
procHandles = win32process.CreateProcess(*procArgs) # run ...
ssh
打开第二个,新的cmd.exe
窗口,可以进行交互。原cmd.exe
包含 Python 的窗口保持打开状态,Python 本身退出,将控制权返回给 cmd.exe
本身。它是可用的,虽然不一致和丑陋。我想这归结为配置
win32process.STARTUPINFO
正确,但即使在阅读了大量关于它的文档之后,我还是无法理解它......
关于python - 如何在 Windows 上有效地 "replace" `os.execvpe` - 如果 "child"进程是交互式命令行应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67371606/