问题描述
我想编写一个程序(在Windows 7的Python 3.x中),通过ssh在远程shell上执行多个命令.看了paramikos的exec_command()
函数之后,我意识到它不适合我的用例(因为在执行命令后通道被关闭了),因为命令取决于环境变量(由先前的命令设置),并且不能连接到一个exec_command()
调用中,因为它们将在程序中的不同时间执行.
I want to write a program (in Python 3.x on Windows 7) that executes multiple commands on a remote shell via ssh. After looking at paramikos' exec_command()
function, I realized it's not suitable for my use case (because the channel gets closed after the command is executed), as the commands depend on environment variables (set by prior commands) and can't be concatenated into one exec_command()
call as they are to be executed at different times in the program.
因此,我想在同一通道中执行命令.我研究的下一个选项是使用paramikos的invoke_shell()
函数实现交互式shell:
Thus, I want to execute commands in the same channel. The next option I looked into was implementing an interactive shell using paramikos' invoke_shell()
function:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=user, password=psw, port=22)
channel = ssh.invoke_shell()
out = channel.recv(9999)
channel.send('cd mivne_final\n')
channel.send('ls\n')
while not channel.recv_ready():
time.sleep(3)
out = channel.recv(9999)
print(out.decode("ascii"))
channel.send('cd ..\n')
channel.send('cd or_fail\n')
channel.send('ls\n')
while not channel.recv_ready():
time.sleep(3)
out = channel.recv(9999)
print(out.decode("ascii"))
channel.send('cd ..\n')
channel.send('cd simulator\n')
channel.send('ls\n')
while not channel.recv_ready():
time.sleep(3)
out = channel.recv(9999)
print(out.decode("ascii"))
ssh.close()
此代码存在一些问题:
- 第一个
print
并不总是打印ls
输出(有时仅打印在第二个print
上). - 第一个
cd
和ls
命令始终出现在输出中(我通过recv
命令获得它们,作为输出的一部分),而随后的所有cd
和ls
命令都是有时打印,有时不打印. - 第二个和第三个
cd
和ls
命令(在打印时)始终出现在第一个ls
输出之前.
- The first
print
doesn't always print thels
output (sometimes it is only printed on the secondprint
). - The first
cd
andls
commands are always present in the output (I get them via therecv
command, as part of the output), while all the followingcd
andls
commands are printed sometimes, and sometimes they aren't. - The second and third
cd
andls
commands (when printed) always appear before the firstls
output.
我对这种不确定性"感到困惑,非常感谢您的帮助.
I'm confused with this "non-determinism" and would very much appreciate your help.
推荐答案
import paramiko
import re
class ShellHandler:
def __init__(self, host, user, psw):
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(host, username=user, password=psw, port=22)
channel = self.ssh.invoke_shell()
self.stdin = channel.makefile('wb')
self.stdout = channel.makefile('r')
def __del__(self):
self.ssh.close()
def execute(self, cmd):
"""
:param cmd: the command to be executed on the remote computer
:examples: execute('ls')
execute('finger')
execute('cd folder_name')
"""
cmd = cmd.strip('\n')
self.stdin.write(cmd + '\n')
finish = 'end of stdOUT buffer. finished with exit status'
echo_cmd = 'echo {} $?'.format(finish)
self.stdin.write(echo_cmd + '\n')
shin = self.stdin
self.stdin.flush()
shout = []
sherr = []
exit_status = 0
for line in self.stdout:
if str(line).startswith(cmd) or str(line).startswith(echo_cmd):
# up for now filled with shell junk from stdin
shout = []
elif str(line).startswith(finish):
# our finish command ends with the exit status
exit_status = int(str(line).rsplit(maxsplit=1)[1])
if exit_status:
# stderr is combined with stdout.
# thus, swap sherr with shout in a case of failure.
sherr = shout
shout = []
break
else:
# get rid of 'coloring and formatting' special characters
shout.append(re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]').sub('', line).
replace('\b', '').replace('\r', ''))
# first and last lines of shout/sherr contain a prompt
if shout and echo_cmd in shout[-1]:
shout.pop()
if shout and cmd in shout[0]:
shout.pop(0)
if sherr and echo_cmd in sherr[-1]:
sherr.pop()
if sherr and cmd in sherr[0]:
sherr.pop(0)
return shin, shout, sherr
这篇关于使用Paramiko在python中通过ssh实现交互式shell?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!