在自动化部署、监控和管理任务中,Python因其简洁性和强大的库支持而成为首选语言之一。本文将引导你构建一个能够在本地或通过SSH远程执行命令的Python脚本,同时解决一个常见的挑战:pause
命令导致的程序挂起。
目标
我们的目标是创建一个脚本,该脚本可以:
- 接收用户输入的命令,无论是本地还是远程。
- 处理
pause
命令,确保脚本不会被挂起。 - 显示所有命令的输出,包括标准输出和标准错误输出。
准备工作
确保你已经安装了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
命令,确保在自动化环境中不会发生挂起。无论是进行系统维护、数据抓取还是任何需要执行命令的任务,这个脚本都将是一个强大的工具。
请根据实际情况调整和扩展上述代码,以满足你的具体需求。此外,考虑到安全性和性能,你可能还需要添加错误处理、日志记录以及对敏感信息(如密码)的加密存储。