使用pexpect传输tar文件到SCP
我正在使用 ssh
登录到一台摄像头上,然后用 scp
把一个压缩文件传过去,接着从这个压缩文件中提取文件,然后运行一个脚本。不过,我在使用 Pexpect 的时候遇到了一些问题。Pexpect 在复制压缩文件的时候超时了,似乎没有等到复制完成就开始了下一步。然后在解压命令的时候也出现了同样的问题。以下是我写的代码:
ssh_newkey = 'Are you sure you want to continue connecting'
copy = pexpect.spawn('ssh service@10.10.10.10')
i=copy.expect([ssh_newkey,'password:',pexpect.EOF])
if i==0:
copy.sendline('yes')
i=copy.expect([ssh_newkey,'password:',pexpect.EOF])
if i==1:
copy.sendline("service")
print 'Password Accepted'
copy.expect('service@user:')
copy.sendline('su - root')
i=copy.expect('Password:')
copy.sendline('root')
i=copy.expect('#')
copy.sendline('cd /tmp')
i=copy.expect("#")
copy.sendline('scp user@20.20.20.20:/home/user/tarfile.tar.gz .')
i=copy.expect([ssh_newkey,'password:',pexpect.EOF])
if i==0:
copy.sendline('yes')
i=copy.expect([ssh_newkey,'password:',pexpect.EOF])
else:
pass
copy.sendline('userpwd')
i=copy.expect('#')
copy.sendline('tar -zxvf tarfile.tar.gz bin/installer.sh')
i=copy.expect("#")
copy.sendline("setsid /tmp/bin/installer.sh /tmp/tarfile.tar.gz > /dev/null 2>&1 &")
elif i==2:
print "I either got key or connection timeout"
else:
pass
有没有人能帮我找到解决办法?
谢谢
2 个回答
1
你为什么要使用 pexpect 或者 paramiko 呢?
如果你设置了一个公钥/私钥,那么你可以用一个简单的例子来操作:
command = "scp user@20.20.20.20:/home/user/tarfile.tar.gz"
split_command = shlex.split(command)
subprocess.call(split_command)
然后根据上面的建议,使用 paramiko 来发送命令。
你也可以用密钥文件来实现这个功能:
下面这个类的方法可以让你保持一个持续的会话(虽然还没有经过测试):
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
from paramiko import SSHClient, AutoAddPolicy, AuthenticationException, RSAKey
from subprocess import call
class CommsSuite(object):
def __init__(self):
self.ssh_client = SSHClient()
#--------------------------------------
def _session_send(command):
"""
Use to send commands over ssh in a 'interactive_session'
Verifies session is present
If the interactive_session is not present then print the failed command.
This may be updated to raise an error,
which would probably make more sense.
@param command: the command to send across as a string
::TODO:: consider raise exception here as failed
session will most likely be fatal.
"""
if self.session.send_ready():
self.session.send("%s\n" % command)
else:
print("Session cannot send %s" % command)
#--------------------------------------
def _get_persistent_session(_timeout = 5):
"""
connect to the host and establish an interactive session.
@param _timeout: sets the timout to prevent blocking.
"""
privatekeyfile = os.path.expanduser('~/.ssh/id_rsa')#this must point to your keyfile
private_key = RSAKey.from_private_key_file(privatekeyfile)
self.ssh_client.set_missing_host_key_policy(AutoAddPolicy())
self.ssh_client.connect(hostname,
username = <username>,
pkey = private_key,
timeout = _timeout)
self.transport = self.ssh_client.get_transport()
self.session = self.transport.open_session()
self.session.exec_command("bash -s")
_get_persistent_session()
# build a comma seperated list of commands here as a string "[a,b,c]"
commands = ["tar -zxvf tarfile.tar.gz bin/installer.sh", "setsid /tmp/bin/installer.sh /tmp/tarfile.tar.gz > /dev/null 2>&1"]
# then run the list of commands
if len(commands) > 0:
for command in commands:
_session_send(command)
self.session.close()#close the session when done
CommsSuite()
2
我不太确定这样做是否正确,但我会尝试把超时时间设置为 None
:
copy = pexpect.spawn('ssh service@10.10.10.10', timeout=None)
根据源代码,pexpect 似乎在超时时间设置为 None
时并不会检查超时。
无论如何,我之所以回答这个问题,即使我不确定这样做是否能解决你的问题,是因为我想推荐你使用 paramiko。我之前用它进行 SSH 通信时体验很好。