【问题标题】:Paramiko / ssh / tail + grep hangsParamiko / ssh / tail + grep 挂起
【发布时间】:2013-01-29 13:59:37
【问题描述】:

情况: 我想用 paramiko 通过 ssh 跟踪远程日志。

channel.exec_command('tail -f log.log') 工作正常

channel.exec_command('tail -f log.log | grep "filter" ') 挂起

无法理解使用 grep 的 tail 挂起的原因。

代码示例:

import paramiko
import select
import re

interesting_line_pattern = re.compile('xxx')

def do_tail():
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    from os.path import expanduser
    home = expanduser("~")
    client.connect('xxx',
                   username='xxx',
                   key_filename='%s/.ssh/id_rsa' % home)

    log_file = '/home/xxx/log.log'
    grep_pattern = "grep_filter"
    remote_command = 'tail -f %s | grep "%s" ' % (log_file, grep_pattern)
    print remote_command

    transport = client.get_transport()
    channel = transport.open_session()
    channel.exec_command(remote_command)

    while 1:
        try:
            rl, _, _ = select.select([channel], [], [], 0.0)
            if len(rl) > 0:
                print "ready to read"
                for line in linesplit(channel):
                    print line

        except (KeyboardInterrupt, SystemExit):
            print 'got ctrl+c'
            break

    client.close()
    print 'client closed'

def linesplit(socket):
    buffer_string = socket.recv(4048)
    done = False
    while not done:
        if "\n" in buffer_string:
            (line, buffer_string) = buffer_string.split("\n", 1)
            yield line + "\n"
        else:
            more = socket.recv(4048)
            if not more:
                done = True
            else:
                buffer_string = buffer_string + more
    if buffer_string:
        yield buffer_string


if __name__ == '__main__':

    do_tail()

【问题讨论】:

    标签: python ssh grep paramiko tail


    【解决方案1】:

    grep 认为它没有写入终端,因此它正在缓冲其输出。其输入的行数不足,无法写入任何输出,因此您认为它已挂起。

    尝试为grep 提供--line-buffered 选项。例如

    channel.exec_command('tail -f log.log | grep --line-buffered "filter" ')
    

    【讨论】:

      【解决方案2】:

      让我分享 linesplit 针对 python >= 3.6 的函数更新

      def linesplit(socket):
      buffer_bytes = socket.recv(4048)
      buffer_string = buffer_bytes.decode()
      done = False
      while not done:
          if "\n" in buffer_string:
              (line, buffer_string) = buffer_string.split("\n", 1)
              yield line + "\n"
          else:
              more = socket.recv(4048)
              if not more:
                  done = True
              else:
                  buffer_string = buffer_string + more.decode()
      if buffer_string:
          yield buffer_string
      

      【讨论】: