我正在尝试实现类似于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__
当然,我最终将它包装成函数。有没有人看到这个问题?
答案 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)
请改用subprocess.Popen。
http://docs.python.org/library/subprocess.html#subprocess-replacements
http://docs.python.org/library/subprocess.html#subprocess.Popen
在os.popen docs中甚至有关于此的说明。
答案 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所需的功能,静默一些虚假的日志消息。)