在 Paramiko 中运行交互式命令
Posted
技术标签:
【中文标题】在 Paramiko 中运行交互式命令【英文标题】:Running interactive commands in Paramiko 【发布时间】:2010-09-27 06:46:07 【问题描述】:我正在尝试通过 paramiko 运行交互式命令。 cmd 执行尝试提示输入密码,但我不知道如何通过 paramiko 的 exec_command 提供密码并且执行挂起。如果 cmd 执行需要交互输入,有没有办法向终端发送值?
ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")
有谁知道如何解决这个问题?谢谢。
【问题讨论】:
这个问题很老了,但是对于那些仍然通过谷歌搜索来到这里的人,我想给他们这个。关键是要获得自己的 频道 Executing Interactive Commands in Python through Paramiko Part 1 @987654322 @ 在这两个视频中,它解释了如何通过 paramiko 运行交互式命令,特别是第二个视频很棒,可能是你需要的。 【参考方案1】:完整的 paramiko 发行版附带了很多优秀的 demos。
在 demos 子目录中,demo.py
和 interactive.py
有完整的交互式 TTY 示例,这对于您的情况来说可能是多余的。
在上面的示例中,ssh_stdin
的作用类似于标准 Python 文件对象,因此只要通道仍处于打开状态,ssh_stdin.write
就应该可以工作。
我从来不需要写信给标准输入,但文档建议一旦命令退出通道就会关闭,因此使用标准的stdin.write
方法发送密码可能不起作用。通道本身有较低级别的 paramiko 命令,可让您获得更多控制权 - 请参阅SSHClient.exec_command
方法是如何实现所有血腥细节的。
【讨论】:
而且,对于那些来到这里只想查看命令输出的人来说,一些代码可能是:(stdin, stdout, stderr) = Client.exec_command('ls -la') print("\nstdout is:\n" + stdout.read() + "\nstderr is:\n" + stderr.read())
修复了断开的链接。【参考方案2】:
我在尝试使用 ssh(Paramiko 的一个分支)创建交互式 ssh 会话时遇到了同样的问题。
我翻遍了,发现这篇文章:
更新的链接(链接生成 404 之前的最后一个版本):http://web.archive.org/web/20170912043432/http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/
要继续您的示例,您可以这样做
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")
ssh_stdin.write('password\n')
ssh_stdin.flush()
output = ssh_stdout.read()
这篇文章更深入,描述了一个围绕 exec_command 的完全交互式的 shell。我发现这比源代码中的示例更容易使用。
原文链接:http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/
【讨论】:
链接坏了:(【参考方案3】:您需要 Pexpect 才能获得两全其美(expect 和 ssh 包装器)。
【讨论】:
我也会推荐这个。这是一个同时控制多台服务器的示例,但它可以很容易地只在一个服务器上使用。 github.com/pexpect/pexpect/blob/master/examples/hive.py【参考方案4】:ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(server_IP,22,username, password)
stdin, stdout, stderr = ssh.exec_command('/Users/lteue/Downloads/uecontrol-CXC_173_6456-R32A01/uecontrol.sh -host localhost ')
alldata = ""
while not stdout.channel.exit_status_ready():
solo_line = ""
# Print stdout data when available
if stdout.channel.recv_ready():
# Retrieve the first 1024 bytes
solo_line = stdout.channel.recv(1024)
alldata += solo_line
if(cmp(solo_line,'uec> ') ==0 ): #Change Conditionals to your code here
if num_of_input == 0 :
data_buffer = ""
for cmd in commandList :
#print cmd
stdin.channel.send(cmd) # send input commmand 1
num_of_input += 1
if num_of_input == 1 :
stdin.channel.send('q \n') # send input commmand 2 , in my code is exit the interactive session, the connect will close.
num_of_input += 1
print alldata
ssh.close()
如果直接使用而不检查stdout.channel.recv_ready(),为什么stdout.read()会挂起:而stdout.channel.exit_status_ready():
就我而言,在远程服务器上运行命令后,会话正在等待用户输入,输入“q”后,它将关闭连接。 但在输入 'q' 之前,stdout.read() 将等待 EOF,如果缓冲区较大,似乎此方法不起作用。
我在 while 中尝试了 stdout.read(1),它可以工作 我在 while 中尝试了 stdout.readline() ,它也有效。 标准输入、标准输出、标准错误 = ssh.exec_command('/Users/lteue/Downloads/uecontrol') stdout.read() 将挂起【讨论】:
如果您需要答案,这应该是一个单独的问题(因为这是一个老问题)。或者至少它应该是对问题或答案之一的评论。它本身不能成为答案。【参考方案5】:我不熟悉 paramiko,但这可能有效:
ssh_stdin.write('input value')
ssh_stdin.flush()
有关标准输入的信息:
http://docs.python.org/library/sys.html?highlight=stdin#sys.stdin
【讨论】:
注意:始终确保以本示例正确显示的方式刷新()您正在写入的任何缓冲区;忘记(或不知道)这样做是令人沮丧的常见原因。【参考方案6】:看例子,类似的做法
(来自http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/):
ssh.connect('127.0.0.1', username='jesse',
password='lol')
stdin, stdout, stderr = ssh.exec_command(
"sudo dmesg")
stdin.write('lol\n')
stdin.flush()
data = stdout.read.splitlines()
for line in data:
if line.split(':')[0] == 'AirPort':
print line
【讨论】:
源链接断开【参考方案7】:您可以使用此方法发送您想要的任何确认消息,例如“OK”或密码。这是我的示例解决方案:
def SpecialConfirmation(command, message, reply):
net_connect.config_mode() # To enter config mode
net_connect.remote_conn.sendall(str(command)+'\n' )
time.sleep(3)
output = net_connect.remote_conn.recv(65535).decode('utf-8')
ReplyAppend=''
if str(message) in output:
for i in range(0,(len(reply))):
ReplyAppend+=str(reply[i])+'\n'
net_connect.remote_conn.sendall(ReplyAppend)
output = net_connect.remote_conn.recv(65535).decode('utf-8')
print (output)
return output
CryptoPkiEnroll=['','','no','no','yes']
output=SpecialConfirmation ('crypto pki enroll TCA','Password' , CryptoPkiEnroll )
print (output)
【讨论】:
以上是关于在 Paramiko 中运行交互式命令的主要内容,如果未能解决你的问题,请参考以下文章
使用python和paramiko在交互式远程shell中运行commnad