使用paramiko exec_command运行命令会导致进程在完成之前进入休眠状态

use*_*020 8 python ssh process paramiko

我正在使用python的paramiko模块SSH到远程机器和Tar/ZIP文件夹中有很多文件(超过14K文件和60 + gig数据).得到的拉链本身约10演出.现在我可以直接从机器上运行zip/tar命令,没有任何问题.但是,当我尝试通过SSHClient的exec_command运行相同的命令时,它运行了一段时间,但最终远程机器上的压缩过程进入休眠状态.而recv_exit_status只是无限期挂起.这是我正在使用的代码:

stdin, stdout, stderr = ssh.exec_command('cd myDirectory; tar -zcvf output.tgz *')
status = stdout.channel.recv_exit_status()
Run Code Online (Sandbox Code Playgroud)

我也试过使用Zip.

stdin, stdout, stderr = ssh.exec_command('cd myDirectory; find -name "*.gz" | zip output.zip -@')
status = stdout.channel.recv_exit_status()
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,如果我直接从远程计算机运行命令,它将完成压缩/ TARing.结果文件就像9演出.但是当我从paramiko尝试它时,它开始,超过一半(6's演出),然后过程进入睡眠状态!

我使用top监视远程机器上的进程,zip/tar将开始运行,但最终会在完成之前进入休眠状态.并且python脚本将无限期挂起.

任何想法为什么会这样?

Dmi*_*rev 2

这可能与超时有关。尝试将timeout参数(以秒为单位)添加到调用中:exec_command(timeout=20*60)。这是 20 分钟的示例。有关更多信息,请参阅该方法的文档字符串:

def exec_command(self, command, bufsize=-1, timeout=None, get_pty=False):
    """
    Execute a command on the SSH server.  A new `.Channel` is opened and
    the requested command is executed.  The command's input and output
    streams are returned as Python ``file``-like objects representing
    stdin, stdout, and stderr.

    :param str command: the command to execute
    :param int bufsize:
        interpreted the same way as by the built-in ``file()`` function in
        Python
    :param int timeout:
        set command's channel timeout. See `Channel.settimeout`.settimeout
    :return:
        the stdin, stdout, and stderr of the executing command, as a
        3-tuple

    :raises SSHException: if the server fails to execute the command
    """
Run Code Online (Sandbox Code Playgroud)

另外,我遇​​到的另一个问题也可能有所贡献:https ://github.com/paramiko/paramiko/issues/109

尝试我的建议https://github.com/paramiko/paramiko/issues/109#issuecomment-111621658

我也遇到了这个问题,这是由于 stdout.channel.eof_received == 0

import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("1.1.1.1", username="root", password="pass")
stdin, stdout, stderr = client.exec_command("service XXX start")
Run Code Online (Sandbox Code Playgroud)

stdin、stdout 和 stderr 保持开放状态...

>>> print stdin
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>
>>> print stdout
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>
>>> print stderr
<paramiko.ChannelFile from <paramiko.Channel 3 (open) window=2097152 in-buffer=50 -> <paramiko.Transport at 0x17eff90L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>>
Run Code Online (Sandbox Code Playgroud)

所以没有收到EOF...

>>> print stdin.channel.eof_received
0
Run Code Online (Sandbox Code Playgroud)

通常我收到 True 并且只能 stdout.read(),但为了安全起见,我使用此解决方法(有效!):等待超时,强制 stdout.channel.close() 然后强制 stdout.read():

>>> timeout = 30
>>> import time
>>> endtime = time.time() + timeout
>>> while not stdout.channel.eof_received:
...     sleep(1)
...     if time.time() > endtime:
...         stdout.channel.close()
...         break
>>> stdout.read()
'Starting XXX: \n[  OK  ]\rProgram started . . .\n'
>>>
Run Code Online (Sandbox Code Playgroud)