簡體   English   中英

如何有效地“替換” Windows 上的 `os.execvpe` - 如果“子”進程是交互式命令行應用程序?

[英]How to "replace" `os.execvpe` on Windows efficiently - if the "child" process is an interactive command line application?

我正在處理一個 Python 腳本,經過一些准備工作后,它會啟動ssh 我的腳本實際上是一個小型 CLI 工具。 在類 Unix 系統上,在其生命周期結束時,Python 腳本將自身替換為ssh客戶端,因此用戶現在可以與遠程機器上的ssh等命令直接交互:

os.execvpe('ssh', ['ssh', '-o', 'foo', 'user@host'], os.environ)

如果您想知道的話,肯定會有驚喜和旁注:Windows 10 實際上現在內置了 OpenSSH 的本機版本,所以在這個平台上有一個ssh命令。

os.execvpe存在於 Windows 上的 Python 標准庫中,但它不會取代原始 (Python) 進程。 情況......有點復雜: 1 , 2 , 3 底線: Windows 沒有實現相應的 POSIX 語義來替換正在運行的進程。

普遍的智慧是使用subprocess.Popen代替,好的,有效地創建一個子進程。 我可以啟動孩子以便父母繼續運行,或者我可以在父母去世時啟動孩子(我認為Windows 確實支持后者,就像類 Unix 系統一樣)。 無論哪種方式,用戶都無法在命令行中與孩子進行交互。

假設我保持父級活着,我現在必須編寫大量代碼來通過父級將用戶 I/O 傳遞給子級/從子級傳遞,例如這樣 后者涉及管理流甚至線程,這取決於它應該表現得如何——很多地方都存在潛在問題和未來的破壞。 我不喜歡這樣做(如果我能避免的話)。

在所描述的場景中,如何有效地替換os.execvpe上的 os.execvpe?


編輯(1):點點滴滴,可能是相關的......

我想這取決於弄清楚如何在將STARTUPINFO object 傳遞給Popen之前正確配置它。 命令行實際上可以在 Windows 中繼承


編輯(2):通過pywin32 - ssh的部分解決方案打開第二個新的cmd window 並且可以與之交互。 原來的 shell 和 Python 保持打開狀態,Python 本身退出:

from win32.Demos.winprocess import Process
from shlex import join
Process(join(['ssh', '-o', 'foo', 'user@host']))

部分和不完整的解決方案如下所示,請參閱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 window 可以與之交互。 The original cmd.exe window with Python in it remains open, Python itself quits, returning control to cmd.exe itself. 它是可用的,盡管不一致且丑陋。

我想這歸結為正確配置win32process.STARTUPINFO ,但即使在閱讀了大量關於它的文檔之后,我還是無法理解它......

您可以使用subprocess.Popensubprocess.call function 而不是os.execvpe 他們有標志shell確保子進程可以獲得stdin 我已經嘗試使用以下代碼在 windows 中:

import os
import subprocess
subprocess.Popen('ssh -o foo user@host', shell=True, env=os.environ)

它有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM