python - 如何在 Windows 上有效地 "replace" `os.execvpe` - 如果 "child"进程是交互式命令行应用程序?

标签 python windows subprocess spawn execvp

我正在处理一个 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):点点滴滴,这可能是相关的......
  • Handle Inheritance I
  • Handle Inheritance II
  • STARTUPINFO in Windows
  • STARTUPINFO in Windows - for Python

  • 我想这取决于弄清楚如何正确配置 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/

    相关文章:

    python - kivy:使用 on_press 事件更改根小部件中嵌套按钮的颜色

    c++ - 简单的 C++ GUI 作为 XUL 的替代品?

    Windows 上的 Python : path as subprocess argument gets modified and generating error

    python - 如何处理异步作业的子批处理?

    python - Openpyxl - 对象没有属性 'load_workbook'

    python - 读取 Fernet Key 导致 ValueError : Fernet key must be 32 url-safe base64-encoded bytes

    python - 在分组 DataFrame 上应用不同聚合的最佳方法

    未收到 C++ Windows 异步 IO 命名管道第一条消息

    windows - 部署时 QSoundEffect 不播放声音

    python - 使用子进程模块并行工作(多进程)