2016-08-25 112 views
1

在Windows後,我從cmd.exe運行下面的Python腳本3.5:Python的輸入()反應遲鈍砰砰

subprocess.run(['C:\\Program Files (x86)\\Putty\\plink.exe', 
       '[email protected]', '-P', '54022', '-i', 'key.ppk', 'exit'])  
input('Press Enter...') 

但是,當它的時候按Enter鍵,控制檯沒有響應。 輸入什麼都不做。文字無法輸入。 Ctrl + C也不做任何事情。 Python必須在任務管理器中被殺死。

我懷疑plink離開控臺處於不良狀態。我可以預防或修復嗎?或者我可以在自己的控制檯中運行ssh命令嗎?這並不理想,但它可以。

或者也許有更好的解決方案通過使用Python的SSH運行遠程命令?

當直接從cmd(沒有Python)運行相同的plink命令時,它仍然保持響應。

+1

[在Plink文檔](http://the.earth.li/~sgtatham/putty/0.53b/htmldoc/Chapter7.html)它是你應該使用'-ssh'選項來確保它正在使用ssh進行自動連接時。也許這就是爲什麼它掛起?你也沒有說你的腳本是否打印了「Press Enter ...」文本。如果沒有,那麼它確實是使腳本掛起的Plink。 – Sevanteri

+0

@ Sevanteri plink命令本身做它應該做的事,大概是通過ssh(我不知道怎麼回事),但我會繼續研究這個選項。 「Press Enter ...」確實是打印出來的,如果我用其他代碼替換它,那麼執行得很好。它不接受任何輸入了。 –

+0

@eryksun雖然我知道如何'bash'不是'gnome-terminal',我不知道Windows的具體細節。但是有意義的是,有一個單獨的'conhost',因爲當你運行一個控制檯應用程序'cmd'時不涉及。謝謝你清理那個。 –

回答

1

進程可能會修改控制檯狀態,然後由於某種原因在退出時無法恢復原始狀態。如果這是一個問題,最簡單的解決方案是通過添加參數creationflags=subprocess.CREATE_NEW_CONSOLE來生成帶有自己的控制檯的子進程。

如果這不是一個選項,或者至少不是首選選項,那麼您可以在運行程序之前捕獲控制檯輸入和屏幕緩衝區的當前模式。然後在孩子退出後恢復之前的模式。請參閱MSDN上的GetConsoleModeSetConsoleMode

這是一個上下文管理器來恢復控制檯的輸入和輸出模式。

import ctypes 
import msvcrt 
import contextlib 

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) 

def _check_bool(result, func, args): 
    if not result: 
     raise ctypes.WinError(ctypes.get_last_error()) 
    return args 

kernel32.GetConsoleMode.errcheck = _check_bool 
kernel32.SetConsoleMode.errcheck = _check_bool 

@contextlib.contextmanager 
def restore_console(): 
    if not kernel32.GetConsoleWindow(): 
     yield # nothing to do 
     return 
    with open(r'\\.\CONIN$', 'r+') as coni: 
     with open(r'\\.\CONOUT$', 'r+') as cono: 
      hI = msvcrt.get_osfhandle(coni.fileno()) 
      hO = msvcrt.get_osfhandle(cono.fileno()) 
      imode = ctypes.c_ulong() 
      omode = ctypes.c_ulong() 
      kernel32.GetConsoleMode(hI, ctypes.byref(imode)) 
      kernel32.GetConsoleMode(hO, ctypes.byref(omode)) 
      yield 
      try: 
       kernel32.SetConsoleMode(hI, imode) 
      finally: 
       kernel32.SetConsoleMode(hO, omode) 

這可以通過擴大GetConsoleCPGetConsoleOutputCPSetConsoleCP,並SetConsoleOutputCP恢復輸入和輸出的代碼頁。它還可以恢復屏幕尺寸,標題等。這是conhost.exe中的所有全局狀態,子進程可以插入。另一方面,控制檯的輸入歷史記錄和別名存儲在每個附加的可執行文件中,因此您不必恢復它們。

+0

我正在使用該上下文管理器,它修復了這個問題,非常感謝:) –