代码如下(未使用sqlalchemy版本):
#!/bin/env python import paramiko import sys import os import socket import getpass from paramiko.py3compat import u import termios #Windows下无此模块 import tty import select ''' 有关终端模式的解释 终端最常用的模式是Cooked模式,在该模式下删除键和终止键能正常地工作,CTRL_S和 CTRL_Q用来停止和恢复终端输出, CTRL_D为文件结束符,按DEL键产生一个中断信号,而CTRL-产生一个退出信号并强制进行核心映像转储。 在raw模式下,所有这些功能都被取消,每个字符都被不加处理地送给程序,而且不等一行结束就将从终端读到每一个字符 发送给程序。与此不同的是在Cooked模式下,终端输入的数据等到一行结束才送给程序。 Cbreak模式介于上述两者之间,用作编辑的删除键和终止键,以及CTRL_D被屏蔽,但CTRL_S,CTRL_Q,DEL和CTRL_则仍然 有效,与raw模式一样,单个字符不等一行结束就送给程序(如果禁止行内编辑功能,则没必要等待接收到完整的一行,因为 用户不可能象在cooked模式下那样改变主意并删除它)。 ''' def posix_shell(chan): oldtty = termios.tcgetattr(sys.stdin) #获取当前终端的模式 try: tty.setraw(sys.stdin.fileno()) #设置终端模式为raw模式 tty.setcbreak(sys.stdin.fileno()) #设置终端模式为cbreak模式 chan.settimeout(0.0) #不对chan超时时间做限制 log = open('handle.log', 'a+', encoding='utf-8') #open一个文件,用来记录历史命令 flag = False #当用户输入table键时,flag才为True,当有内容返回时,判断flag是否为True,如果为True, # 如果返回值.startswith(' ')为空,不做任何操作,如果返回值不为空,将返回值加到temp_list列表 # 中(因为返回值是用户敲命令是补全的命令后半截) temp_list = [] #用来存放用户输入,即记录历史命令 while True: r, w, e = select.select([chan, sys.stdin], [], []) if chan in r: #chan in r时,说明有返回值 try: x = u(chan.recv(1024)) #获取返回内容 if len(x) == 0: #如果返回值长度为0,代表用户输入exit退出了 sys.stdout.write(' *** EOF ') break if flag: #上方定义flag时已解释 if x.startswith(' '): pass else: temp_list.append(x) flag = False #最后将flag还原为False sys.stdout.write(x) #输出返回值到屏幕 sys.stdout.flush() except socket.timeout: pass if sys.stdin in r: #sys.stdin in r时,说明用户用输入内容 x = sys.stdin.read(1) #输出用户输入的内容到屏幕 #说明,因为当前终端模式为cblock模式 if len(x) == 0: break if x == ' ': #这里将flag设置为True,具体以上定义flag时有解释 flag = True else: temp_list.append(x) #将用户的输入内容append到一个临时列表中 if x == ' ': #代表用户输入回车 log.write(''.join(temp_list)) #''.join(temp_list)为用户敲的命令,将命令写入到日志文件中 log.flush() temp_list.clear() #清空临时列表 chan.send(x) #发送用户的输入内容到远程主机 finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) #将终端模式还原为最初模式 def run(): """ 让用户输入主机名,用户名并设置默认用户名等 :return: """ default_username = getpass.getuser() #获取当前登录用户的用户名 username = input('Username [%s]: ' % default_username) if len(username) == 0: username = default_username hostname = input('Hostname: ') if len(hostname) == 0: print('*** Hostname required.') sys.exit(1) tran = paramiko.Transport((hostname, 22,)) #创建一个连接 tran.start_client() default_auth = "p" auth = input('Auth by (p)assword or (r)sa key[%s] ' % default_auth) if len(auth) == 0: auth = default_auth if auth == 'r': default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa') path = input('RSA key [%s]: ' % default_path) if len(path) == 0: path = default_path try: key = paramiko.RSAKey.from_private_key_file(path) except paramiko.PasswordRequiredException: password = getpass.getpass('RSA key password: ') key = paramiko.RSAKey.from_private_key_file(path, password) tran.auth_publickey(username, key) else: pw = getpass.getpass('Password for %s@%s: ' % (username, hostname)) tran.auth_password(username, pw) # 打开一个通道 chan = tran.open_session() # 获取一个终端 chan.get_pty() # 激活器 chan.invoke_shell() posix_shell(chan) chan.close() tran.close() if __name__ == '__main__': run()