python ssh stdout multiple

时间:2014-05-22 15:33:48

标签: python ssh stdout

在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()

3 个答案:

答案 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()的一个例子,看看它有多乱。)

但是,更简洁的是使用paramiko,它提供了更高级别的抽象来处理ssh连接。特别是,请查看paramiko.client.SSHClient类的示例用法。

答案 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'来改善。并相应地建立一个正则表达式。