在python中,我试图通过ssh连接并逐个播放多个命令。 此代码工作正常,输出打印到我的屏幕:
cmd = ['ssh', '-t', '-t', 'user@host']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
p.stdin.write('pwd\n')
p.stdin.write('ls -l\n')
p.stdin.write('exit\n')
p.stdin.close()
我的问题是当我尝试在字符串中获取每个响应时。我试过这个但是read函数阻塞了:
cmd = ['ssh', '-t', '-t', 'user@host']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.write('pwd\n')
st1 = p.stdout.read()
p.stdin.write('ls -l\n')
st2 = p.stdout.read()
p.stdin.close()
答案 0 :(得分:2)
我同意Alp的看法,让你有一个库为你做连接逻辑可能更容易。 pexpect是一种方法。以下是paramiko的一个例子。 http://docs.paramiko.org/en/1.13/
import paramiko
host = 'myhost'
port, user, password = '22', 'myuser', 'mypass'
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.load_system_host_keys()
client.connect(host, port, user, password, timeout=10)
command = 'ls -l'
stdin, stdout, stderr = client.exec_command(command)
errors = stderr.read()
output = stdout.read()
client.close()
答案 1 :(得分:1)
read()
调用正在阻止,因为在没有参数调用时,read()
将从相关流中读取,直到遇到EOF
。
如果您的用例与示例代码一样简单,那么便宜的解决方法是在关闭连接之后推迟从p.stdout
读取:
cmd = ['ssh', '-t', '-t', 'deploy@pdb0']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.write('pwd\n')
p.stdin.write('ls -l\n')
p.stdin.write('exit\n')
p.stdin.close()
outstr = p.stdout.read()
然后,您必须解析outstr
以分隔不同comamnds的输出。 (寻找远程shell提示符的出现可能是最直接的方法。)
如果在发送另一个命令之前需要读取一个命令的完整输出,则有几个问题。首先,这可以阻止:
p.stdin.write('pwd\n')
st1 = p.stdout.read()
因为您写入p.stdin
的命令可能会被缓冲。您需要在查找输出之前刷新命令:
p.stdin.write('pwd\n')
p.stdin.flush()
st1 = p.stdout.read()
read()
来电仍然会阻止。您要做的是使用指定的缓冲区大小调用read()
并以块的形式读取输出,直到再次遇到远程shell提示符。但即便如此,您仍然需要使用select
来检查p.stdout
的状态,以确保您不会阻止。
有一个名为pexpect的库可以为您实现该逻辑。使用它会更容易(或者更好的是pxssh
,它专门用于pexpect
用于ssh连接),因为使一切正常是相当毛茸茸的,并且不同的OS在行为上有所不同边缘情况。 (看看pexpect.spawn.read_nonblocking()
的一个例子,看看它有多乱。)
答案 2 :(得分:1)
感谢你们两位的回答。为了简单起见,我用以下代码更新了我的代码:
def getAnswer(p, cmnd):
# send my command
if len(cmnd) > 0:
p.stdin.write(cmnd + '\n')
p.stdin.flush()
# get reply -- until prompt received
st = ""
while True:
char = p.stdout.read(1)
st += char
if char == '>':
return st
cmd = ['ssh', '-t', '-t', 'user@host']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
#discard welcome message
getAnswer(p, '')
st1 = getAnswer(p, 'pwd')
st2 = getAnswer(p, 'ls -l')
...
p.stdin.write('exit\n')
p.stdin.flush()
p.stdin.close()
p.stdout.close()
这不完美但工作正常。为了检测提示,我只是在等待'>'这可以通过首先发送回声$ PS1'来改善。并相应地建立一个正则表达式。