在Windows上,我正在运行cmd.exe
的以下Python 3.5脚本:
subprocess.run(['C:\\Program Files (x86)\\Putty\\plink.exe',
'root@server', '-P', '54022', '-i', 'key.ppk', 'exit'])
input('Press Enter...')
但是当按下Enter时,控制台没有响应。 输入什么都不做。无法输入文字。 Ctrl + C 也没有做任何事情。必须在任务管理器中杀死Python。
我怀疑plink
正在使控制台处于不良状态。我可以预防或修复这个吗?或者我可以在自己的控制台中运行ssh命令吗?这不太理想,但它会做到。
或许使用Python通过SSH运行远程命令有更好的解决方案吗?
直接从plink
(没有Python)运行相同的cmd
命令时,它确实保持响应。
答案 0 :(得分:1)
进程可能会修改控制台状态,然后由于某种原因无法在退出时恢复原始状态。如果这是一个问题,最简单的解决方案是通过添加参数creationflags=subprocess.CREATE_NEW_CONSOLE
来使用自己的控制台生成子进程。
如果这不是一个选项,或者至少不是首选选项,则可以在运行程序之前捕获控制台输入和屏幕缓冲区的当前模式。然后在孩子退出后恢复以前的模式。请参阅MSDN上的GetConsoleMode
和SetConsoleMode
。
这是一个恢复控制台输入和输出模式的上下文管理器。
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)
可以通过GetConsoleCP
,GetConsoleOutputCP
,SetConsoleCP
和SetConsoleOutputCP
扩展此功能以恢复输入和输出代码页。它还可以恢复屏幕尺寸,标题等。这是子进程可以插入的conhost.exe中的全局状态。另一方面,控制台的输入历史记录和别名是按照附加的可执行文件存储的,因此您不必恢复它们。