如何用Python/Paramiko脚本忽略MOTD与Banner消息并保存命令输出
Hey there! Nice work getting this far with only 3 months of Python experience—you’re already building useful automation tools, which is awesome. Let’s fix up your script to filter out those annoying banners/MOTDs and save only the actual command output to your specified file. Here’s how to do it step by step:
Key Issues to Fix
Right now, your script prints everything it receives from the SSH connection, including login banners, command echoes, and MOTDs. We need to:
- Skip the initial login output (banner/MOTD)
- Filter out the command lines themselves (since you don’t want to see
hardware cecplus...repeated in your output) - Write only the actual command results to your target file instead of just printing them
Modified Script with Explanations
Here’s the updated code with these changes— I’ll highlight the key tweaks below:
from __future__ import print_function import threading import paramiko import getpass import time import os import sys os.system('clear') class ssh(object): shell = None client = None transport = None output_file = None sent_commands = [] # Track commands we've sent to filter echoes def __init__(self, address, username, password, output_file): print('Connecting to server on ip', str(address.strip()) + '.') self.output_file = output_file self.client = paramiko.client.SSHClient() self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy()) try: self.client.connect(address.strip(), username=username, password=password, look_for_keys=False) self.transport = self.client.get_transport() # Reuse the client's transport instead of creating a new one thread = threading.Thread(target=self.process) thread.daemon = True thread.start() except Exception as e: print(f'Failed to connect to {address.strip()}: {str(e)}') self.client = None def close_connection(self): if self.client is not None: self.client.close() if self.transport is not None: self.transport.close() def open_shell(self, prompt='#'): # Add prompt parameter to match your server's prompt if self.client is None: print("No active connection to open shell on.") return self.shell = self.client.invoke_shell() # Read and discard initial banner/MOTD until we see the prompt while True: if self.shell.recv_ready(): data = self.shell.recv(1024).decode('utf-8') if prompt in data: break # Stop once we get to the command prompt def send_shell(self, command): if self.shell and self.client is not None: self.sent_commands.append(command) self.shell.send(command + '\n') else: print("Shell not opened or connection failed.") def process(self): if self.client is None: return while True: if self.shell is not None and self.shell.recv_ready(): alldata = self.shell.recv(1024).decode('utf-8') while self.shell.recv_ready(): alldata += self.shell.recv(1024).decode('utf-8') # Split into lines and filter unwanted content lines = alldata.split(os.linesep) for line in lines: stripped_line = line.strip() # Skip empty lines, command echoes, and any leftover prompt text if not stripped_line: continue if any(cmd in stripped_line for cmd in self.sent_commands): continue if stripped_line.endswith('#') or stripped_line.endswith('>'): continue # Write the clean output to file and print (optional) print(stripped_line) self.output_file.write(stripped_line + os.linesep) self.output_file.flush() # Ensure data is written immediately header = "################## WHAT DO YOU WANT TO DO?? ##################" headlen = len(header) - 2 secondline = "|" + (" " * headlen) + "|" thirdline = "|" + " 1. Run the daily ATM Script." + (" " * 30) + "|" fourthline = "|" + " 2. Run a single command on the entire ATM network" + (" " * 9) + "|" print(header) print(secondline) print(secondline) print(thirdline) print(fourthline) print(secondline) print(secondline) print("#" * len(header)) choice = raw_input("Choose your destiny: ") while choice: if choice == "1": print(' \n##### STARTING PROGRAM #####\n') sshUsername = getpass.getpass(prompt='ENTER USERNAME: ') sshPassword = getpass.getpass('ENTER PASSWORD: ') filename = raw_input("What filename dost thou chooseth? ") # Open file in write mode (use 'a' if you want to append instead) with open(filename, 'w') as writefile: def main(): with open("host.csv", "r") as r: for address in r: address = address.strip() if not address: continue # Skip empty lines in host.csv print(f"\nProcessing {address}...") connection = ssh(address, sshUsername, sshPassword, writefile) if connection.client is None: writefile.write(f"FAILED TO CONNECT TO: {address}{os.linesep}") continue try: connection.open_shell() # Adjust prompt here if your server uses something else like '>' time.sleep(1) commands = [ 'hardware cecplus timing references show', 'power', 'hard port show', 'sig show', 'conn spvcc pp show', 'interface sonet path near total' ] for cmd in commands: connection.send_shell(cmd) time.sleep(1) # Adjust sleep time based on how long commands take to run time.sleep(2) # Give time for final output to come through except Exception as e: error_msg = f'Failed to run commands on {address}: {str(e)}' print(error_msg) writefile.write(error_msg + os.linesep) finally: connection.close_connection() main() print(f"\nAll tasks completed! Output saved to {filename}") break elif choice == "2": COMMAND = raw_input("INPUT A SINGLE COMMAND TO RUN ON THE ENTIRE ATM NETWORK: ") print(' \n##### STARTING PROGRAM #####\n') sshUsername = getpass.getpass(prompt='ENTER USERNAME: ') sshPassword = getpass.getpass('ENTER PASSWORD: ') filename = raw_input("What filename dost thou chooseth? ") with open(filename, 'w') as writefile: def main(): with open("host.csv", "r") as r: for address in r: address = address.strip() if not address: continue print(f"\nProcessing {address}...") connection = ssh(address, sshUsername, sshPassword, writefile) if connection.client is None: writefile.write(f"FAILED TO CONNECT TO: {address}{os.linesep}") continue try: connection.open_shell() time.sleep(1) connection.send_shell(COMMAND) time.sleep(2) except Exception as e: error_msg = f'Failed to run command on {address}: {str(e)}' print(error_msg) writefile.write(error_msg + os.linesep) finally: connection.close_connection() main() print(f"\nAll tasks completed! Output saved to {filename}") break else: print("If thou dost not Enter 1 or 2 thou willest not proceed") choice = raw_input("Choose your destiny: ")
Key Tweaks Explained
SSH Class Improvements:
- Added an
output_fileparameter to the__init__method so each connection knows where to write results. - Added a
sent_commandslist to track commands we’ve sent—this lets us filter out the command echoes from the output. - Updated
open_shellto read and discard the initial banner/MOTD until it detects the server’s command prompt (adjust thepromptparameter if your server uses something like>instead of#). - The
processmethod now filters out empty lines, command echoes, and prompt text, then writes clean output to your file.
- Added an
Main Program Fixes:
- Now uses
with open(...)for both the output file andhost.csvto ensure files are properly closed. - Skips empty lines in
host.csvto avoid errors. - Adds error messages to the output file so you can track failed connections/commands.
- Adjusted sleep times to give commands enough time to run and return output (you might need to tweak these based on your servers’ response speed).
- Now uses
Other Small Fixes:
- Reused the client’s transport instead of creating a new one (avoids redundant connections).
- Added
.strip()to IP addresses to remove newline characters fromhost.csv. - Flushes the output file after each write to ensure data is saved immediately.
Give this a try—you should now get only the actual command results in your output file, with no banners or MOTDs cluttering things up. Let me know if you need to adjust the prompt or sleep times for your specific servers!
内容的提问来源于stack exchange,提问作者wiz0rd

