从python分页输出

时间:2011-07-18 04:34:51

标签: python

我正在尝试实现类似于git log的内容,只有在日志长度达到一定时才会对输出进行分页。如果你不熟悉git,我基本上是想实现这个目标:

python some_script.py | less

在python2.6 / pydoc.py的分页实现的帮助下,我能够想出这个:

import os
text = '...some text...'
pipe = os.popen('less', 'w')
pipe.write(text)
pipe.close()

效果很好,但不推荐使用os.popen()。我考虑过写一个临时文件并用它的路径调用较少,但这似乎并不理想。子进程可以实现吗?还有其他想法吗?

编辑:

所以我已经让子进程工作了。我能够用Popen.communicate(text)给它文本变量,但由于我真的想重定向打印语句,我已经确定了这个:

  import os, sys, subprocess, tempfile

  page = True
  if page:
      path = tempfile.mkstemp()[1]
      tmp_file = open(path, 'a')
      sys.stdout = tmp_file
  print '...some text...'
  if page:
      tmp_file.flush()
      tmp_file.close()
      p = subprocess.Popen(['less', path], stdin=subprocess.PIPE)
      p.communicate()
      sys.stdout = sys.__stdout__     

当然,我最终将它包装成函数。有没有人看到这个问题?

5 个答案:

答案 0 :(得分:33)

这个怎么样:

import pydoc
text = '... some text ... '
pydoc.pager(text)

这(在我的opensuse linux框中)将文本发送到寻呼机(在我的情况下为'less'),并且与在Python解释器中调用“help(... python command ...)”的工作方式相同。

答案 1 :(得分:4)

在代码中明确表示是一个好主意,因此它表明您使用特殊的打印函数printc()而不是标准函数。使用subprocess.call()也足够了(您不需要管道机械)。此外,您可以通过不存储临时文件的名称来保存变量:

from __future__ import print_function

import subprocess, tempfile

page = True  # For tests

# Definition of a printc() function that prints to the correct output
if page:
    tmp_file = open(tempfile.mkstemp()[1], 'w')  # No need to store the name in a specific variable
    def printc(*largs, **kwargs):
        if 'file' not in kwargs:  # The code can still use the usual file argument of print()
            kwargs['file'] = tmp_file  # Forces the output to go to the temp file
        print(*largs, **kwargs)
else:
    printc = print  # Regular print

# Main program:

printc('...some text...', 'some more text', sep='/')  # Python3 syntax

# Paging of the current contents of the temp file:
if page:
    tmp_file.flush()  # No need to close the file: you can keep printing to it
    subprocess.call(['less', tmp_file.name])  # Simpler than a full Popen()

通过这种方式,您可以获得Python 3 print函数的灵活性,其代码可以明确显示您正在进行一些精美的打印工作。对于较大的程序,这比在代码的某些位置修改“全局”sys.stdout变量更好。

答案 2 :(得分:3)

答案 3 :(得分:2)

我不喜欢执行外部命令,因此我在纯Python中编写了pager。它仍有问题 - 管道输入仅适用于Windows。

答案 4 :(得分:0)

有一个警告,对于我来说,这是一种将过程输出重定向到Linux上的寻呼机的方式(我没有Windows可以方便地在那里进行测试),无论出于何种原因,都无法将其全部写到Linux上。文件或StringIO,然后一次将其全部馈送到寻呼机:

import os, sys

less = None
if os.isatty(sys.stdout.fileno()):
    less = subprocess.Popen(
        ['less', '-R', '--quit-if-one-screen'],
        stdin=subprocess.PIPE)
    os.dup2(less.stdin.fileno(), sys.stdout.fileno())

现在要告诫:

less的行为就像已通过-E并在我到达输出的底部时终止。我认为这是因为,作为脚本的子级,它在脚本执行时就死了,但是在脚本末尾添加以下内容只会导致less挂起,否则它将退出并且我没有是时候找出原因了:

if less:
    less.stdin.close()  # no different with or without
    less.communicate()  # no different with less.wait()

(当我第一次提出此技巧时,这不是问题,因为我将其创建为使PyGTK 2.x程序将其输出通过管道传递到grep,以解决PyGTK问题,而不暴露GTK + C API所需的功能,静默一些虚假的日志消息。)