plink

时间:2016-08-25 16:09:48

标签: python windows putty windows-console plink

在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命令时,它确实保持响应。

1 个答案:

答案 0 :(得分: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)

可以通过GetConsoleCPGetConsoleOutputCPSetConsoleCPSetConsoleOutputCP扩展此功能以恢复输入和输出代码页。它还可以恢复屏幕尺寸,标题等。这是子进程可以插入的conhost.exe中的全局状态。另一方面,控制台的输入历史记录和别名是按照附加的可执行文件存储的,因此您不必恢复它们。