You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python subprocess.Popen执行SSH遇密码请求无法终止问题

解决SSH指纹检查脚本因密码请求挂起的问题

最近我在写Python脚本处理工作站重映像后的SSH指纹问题:尝试通过SSH连接目标节点,收到指纹变更警告就处理;但如果没有错误,SSH会触发密码请求,这时候我想终止进程,结果脚本直接挂起了。更奇怪的是,在PyCharm里运行脚本完全正常,能顺利终止SSH并继续执行,但终端里运行就会卡壳。

先贴出我最开始的代码:

def ssh_fingerprint_changed(node):
    """
    Checks if a node's ssh fingerprint has changed or an old key is found, which can occur when a node is reimaged.
    It does this by attempting to connect via ssh and inspecting stdout for an error message.
    :param node: the ip or hostname of the node
    :return: True if the node's fingerprint doesn't match the client's records. Else False.
    """
    changed = False
    cmd = ["ssh", "-q", ADMIN_USER + "@" + node, "exit"]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
    print("Checking for fingerprint changes")
    for line in proc.stdout:
        # loop on lines
        print("in for loop") # NEVER REACHES HERE IF NO ERRORS, WAITING FOR PASSWORD
        if b"Offending key" in line:
            print("Offending key found.")
            proc.stdin.write(b"no\n") # don't connect
            changed = True
        elif b"REMOTE HOST IDENTIFICATION HAS CHANGED!" in line:
            print("REMOTE HOST IDENTIFICATION HAS CHANGED!")
            changed = True
    print(changed) # NEVER REACHES HERE IF NO ERRORS, WAITING FOR PASSWORD
    if not changed:
        # then everything's good, but it will be waiting for a password to connect
        print("Good to go, terminating ssh test.")
        rc = proc.terminate()
    else:
        rc = proc.wait()
    return changed

问题根源拆解

折腾了半天,终于搞清楚两个核心问题:

  1. SSH的输出流向错了:不管是指纹变更的警告,还是密码请求的提示,SSH都是输出到stderr而不是stdout!我之前只监听了stdout,所以完全捕获不到这些信息,当没有指纹问题时,SSH卡在等待密码输入的状态,导致循环一直阻塞,根本到不了后面的proc.terminate()代码。
  2. 终端和PyCharm的stdin差异:PyCharm运行脚本时,子进程的stdin不是交互式终端,SSH检测到无法进行交互式输入,直接就退出了;但终端里的stdin是交互式的,SSH会一直等用户输密码,自然就挂住了。

修复后的代码

针对这两个问题,我修改了脚本,核心是禁用SSH的交互模式,同时正确捕获stderr:

import subprocess
import select

# 替换成你的实际管理员用户名
ADMIN_USER = "admin"

def ssh_fingerprint_changed(node):
    """
    Checks if a node's ssh fingerprint has changed or an old key is found, which can occur when a node is reimaged.
    It does this by attempting to connect via ssh and inspecting output for an error message.
    :param node: the ip or hostname of the node
    :return: True if the node's fingerprint doesn't match the client's records. Else False.
    """
    changed = False
    # 添加BatchMode=yes禁用密码交互,避免挂起;-q减少冗余输出
    cmd = ["ssh", "-q", "-o", "BatchMode=yes", f"{ADMIN_USER}@{node}", "exit"]
    # 同时捕获stdout和stderr,确保拿到所有输出
    proc = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE,
        universal_newlines=True
    )
    
    print("Checking for fingerprint changes")
    
    # 使用select监听两个流,避免单一流阻塞导致脚本挂起
    active_streams = [proc.stdout, proc.stderr]
    while active_streams:
        # 等待可读的流
        readable, _, _ = select.select(active_streams, [], [])
        for stream in readable:
            line = stream.readline()
            # 如果流已经读完,移除它
            if not line:
                active_streams.remove(stream)
                continue
            # 检查指纹相关错误
            if "Offending key" in line:
                print("Offending key found.")
                changed = True
            elif "REMOTE HOST IDENTIFICATION HAS CHANGED!" in line:
                print("REMOTE HOST IDENTIFICATION HAS CHANGED!")
                changed = True
    
    # 设置超时等待进程结束,防止意外阻塞
    try:
        proc.wait(timeout=5)
    except subprocess.TimeoutExpired:
        proc.kill()
    
    print(f"Fingerprint change detected: {changed}")
    return changed

关键修改点说明

  • -o BatchMode=yes:强制SSH禁用所有交互式输入(包括密码请求),如果不能通过密钥认证,直接退出,彻底避免挂起等待输入的情况。
  • 捕获stderr:终于能拿到SSH的所有错误信息了,指纹警告、认证失败的提示都在这里。
  • select模块监听流:避免因为某一个流没有输出而阻塞循环,确保能读取到所有输出内容。
  • 超时等待:给proc.wait()加了5秒超时,就算有意外情况,也不会一直卡着。

现在不管在终端还是PyCharm里运行,脚本都能正常工作,不会再因为密码请求挂起了。

内容的提问来源于stack exchange,提问作者43Tesseracts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:43:36