如何在Python中构建本地和远程命令执行脚本:处理pause命令的挑战

在自动化部署、监控和管理任务中,Python因其简洁性和强大的库支持而成为首选语言之一。本文将引导你构建一个能够在本地或通过SSH远程执行命令的Python脚本,同时解决一个常见的挑战:pause命令导致的程序挂起。

目标

我们的目标是创建一个脚本,该脚本可以:

  1. 接收用户输入的命令,无论是本地还是远程。
  2. 处理pause命令,确保脚本不会被挂起。
  3. 显示所有命令的输出,包括标准输出和标准错误输出。

准备工作

确保你已经安装了Python和paramiko库。paramiko库用于SSH连接,可以使用pip安装:

pip install paramiko

编写脚本

本地命令执行

使用subprocess模块可以轻松地在本地执行命令。我们首先需要确保命令中不包含pause,因为它会阻止自动化脚本的正常运行。

import subprocess def execute_local_command_with_conpty(command): # 移除命令中的pause command = [cmd for cmd in command if cmd != "pause"] # 创建子进程 # ...(此处省略了创建子进程的代码,参考前面提供的代码) # 读取并打印输出 # ...(此处省略了读取输出的代码,参考前面提供的代码)

远程命令执行

使用paramiko库可以通过SSH执行远程命令。我们将使用paramiko.SSHClient连接到远程主机,并通过打开一个会话来执行命令。

import paramiko def ssh_execute_command(host, username, password, command): # 创建SSH客户端 ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 连接到远程主机 ssh.connect(host, username=username, password=password) # 打开会话并执行命令 # ...(此处省略了执行命令的代码,参考前面提供的代码) # 收集并返回所有输出 # ...(此处省略了收集输出的代码,参考前面提供的代码)

整合本地和远程执行

接下来,我们构建一个主函数,根据用户输入判断是本地执行还是远程执行命令。

def main(): # 请求用户输入远程主机信息 # ...(此处省略了请求用户输入的代码,参考前面提供的代码) while True: # 获取用户输入的命令 # ...(此处省略了获取命令的代码,参考前面提供的代码) try: if host and username and password: # 远程执行 # ...(此处省略了远程执行的代码,参考前面提供的代码) else: # 本地执行 # ...(此处省略了本地执行的代码,参考前面提供的代码) except Exception as e: print(f"发生错误:{e}")

import subprocess
import sys
import getpass
import paramiko


def execute_local_command_with_conpty(command):
    # 如果命令中包含pause,从列表中移除
    if "pause" in command:
        command = [cmd for cmd in command if cmd != "pause"]

    # 创建一个子进程,使用conpty来启动命令
    si = subprocess.STARTUPINFO()
    si.dwFlags |= subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW
    si.wShowWindow = subprocess.SW_HIDE
    si.lpDesktop = None
    si.hStdInput = subprocess.PIPE
    si.hStdOutput = subprocess.PIPE
    si.hStdError = subprocess.STD_OUTPUT_HANDLE

    try:
        process = subprocess.Popen(
            command,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            startupinfo=si,
            creationflags=subprocess.CREATE_NEW_CONSOLE,
            universal_newlines=True,
            bufsize=1,
        )

        # 读取子进程的输出并打印
        while True:
            output = process.stdout.readline()
            if output == "" and process.poll() is not None:
                break
            if output:
                sys.stdout.write(output)
                sys.stdout.flush()
    finally:
        process.stdin.close()
        process.stdout.close()
        process.wait()


def ssh_execute_command(host, username, password, command):
    # 创建SSH客户端
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    # 连接到远程主机
    ssh.connect(host, username=username, password=password)

    # 执行命令
    chan = ssh.get_transport().open_session()
    chan.get_pty()
    chan.exec_command(command)

    # 获取命令输出
    output = ""
    error_output = ""
    while True:
        if chan.recv_ready():
            output += chan.recv(1024).decode("utf-8")
        if chan.recv_stderr_ready():
            error_output += chan.recv_stderr(1024).decode("utf-8")
        if chan.exit_status_ready():
            break

    # 关闭SSH连接
    ssh.close()

    # 合并输出结果
    all_output = output + error_output
    return all_output


def main():
    print("开始使用 conpty 进行命令执行循环...")
    host = input("请输入远程主机IP(留空表示本地执行): ")
    username = input("请输入用户名(留空表示本地执行): ")
    password = getpass.getpass("请输入密码(留空表示本地执行): ")

    while True:
        command = input("请输入要执行的命令(或输入 'exit' 退出): ")
        if command.lower() == "exit":
            break

        try:
            if host and username and password:
                # 远程执行
                all_output = ssh_execute_command(host, username, password, command)
                print(all_output)
            else:
                # 本地执行
                command_list = command.split()
                execute_local_command_with_conpty(command_list)
        except Exception as e:
            print(f"发生错误:{e}")


if __name__ == "__main__":
    main()

结论

通过以上步骤,你现在已经有了一个可以处理本地和远程命令执行的Python脚本。这个脚本还能够智能地处理pause命令,确保在自动化环境中不会发生挂起。无论是进行系统维护、数据抓取还是任何需要执行命令的任务,这个脚本都将是一个强大的工具。


请根据实际情况调整和扩展上述代码,以满足你的具体需求。此外,考虑到安全性和性能,你可能还需要添加错误处理、日志记录以及对敏感信息(如密码)的加密存储。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值