8

我正在使用 Python 的 Paramiko 模块通过 SSH 连接到远程机器并使用 Tar/ZIP 压缩一个包含大量文件(超过 14K 文件和 60 多个数据)的文件夹。由此产生的拉链本身约为 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()

我也尝试过使用 Zip。

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

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

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

任何想法为什么会发生这种情况?

4

3 回答 3

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
    """

此外,我遇到的另一个问题也可能有所贡献: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")

标准输入、标准输出和标准错误保持开放......

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

所以没有收到EOF...

>>> print stdin.channel.eof_received
0

通常我会收到 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'
>>>
于 2016-04-20T07:26:59.340 回答
0

我的解决方案是client.exec_command('my_cmd', get_pty=True)

get_pty=True可以从服务器请求一个伪终端

所以如果你可以在 ssh 会话中运行你的命令,那么也应该通过使用exec_command()函数来工作。

于 2018-11-28T07:47:42.183 回答
-1

我刚刚也有类似的事情发生在我身上。我可以在通过 ssh 登录时运行命令,但运行exec_command最终会使命令进入睡眠状态(Sin htop)。我发现这可能是由于命令产生的输出过多,stderr或者stdout我收集到的输出可能会溢出缓冲区,导致命令完成的信号丢失,但我绝对不是专家。我确实发现,添加> /dev/null 2>&1到我的命令末尾(从而消除 paramiko 触摸stdout和的需要stderr)允许相同的命令通过exec_command.

总之,我的工作流程如下所示:

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('999.99.99.99', username='me', key_filename='my_key')

stdin, stdout, stderr = ssh.exec_command('my_command > /dev/null 2>&1')

stdout_content = stdout.read()
stderr_content = stderr.read()
ssh.close()

这目前有效,但如果有人知道如何解决原始问题无需更改命令以重定向stdoutstderr.

于 2018-04-26T21:04:17.867 回答