2011-07-18 18 views
16

我試圖實現類似於git log的東西,如果日誌具有一定的長度,它只會分頁輸出。如果你不熟悉的git,我基本上是試圖實現這一點:來自python的分頁輸出

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

幾點評論:(1)臨時文件名是唯一的:開放模式應該是'w',而不是'a'(不可能附加到文件)。 (2)在閱讀文件之前不需要關閉()。 (3)不需要與尋呼機進程通信(一個簡單的'subprocess.call()'就足夠了)。 (4)更明確的是不要篡改全局像'sys.stdout';除非你真的需要這樣做(就像你想重定向你使用的所有子模塊的輸出一樣),明確地調用一個特殊的打印函數是一個好主意。 – EOL

+0

這是類似的主題,很好,很精緻答案:http://stackoverflow.com/questions/37584717/how-to-write-python-script-with-man-page-like-output/ – user3019074

回答

3
+0

是的,那是我嘗試的第一件事。開始時無法工作,但現在是這樣。謝謝。 – nren

+0

當然。我給了你。如果您有任何問題,我希望獲得一些更一般的實施建議 - 請參閱我的編輯。 – nren

+0

希望我可以幫助你更多,但我現在在Windows上,並且這些工作都不適合我,即使提供的MSYS提供的路徑更少。 – agf

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變得更好。

+1

感謝您的建議!我已經添加了您的優化。我確實需要重定向子模塊的輸出,就像你在註釋中提到的那樣,所以看起來我被困在了sys.stdout方法中。我把這一切都放到一個類中,所以可以用'pager = Pager()'和'pager.begin()'來調用它。 – nren

28

如何:

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

這(在我的openSUSE Linux機器)發送文本尋呼機(在我的情況「少」),並且其工作方式與調用「幫助(... python命令...)「在Python解釋器中。

+3

雖然我懷疑這個函數在將來是不可用的,[很遺憾](https://docs.python.org/3.5/library/pydoc.html),不幸的是,在原理上它並不完全保證它將保持可用。鑑於它的便利性,我認爲這是一種應該經常值得的風險。而且,[源代碼](https://hg.python.org/cpython/file/3.5/Lib/pydoc.py#l1406)看起來好像可以很容易地複製。 – EOL

+0

當試圖打印格式化的json數據時,它會中斷我的輸出。 –

2

我不喜歡執行外部命令,所以我在純Python中編寫了pager。它仍然存在問題 - 管道輸入僅適用於Windows。

+0

尋呼機模塊不能使用unicode :( – MichaelR

+0

@MichaelR,請在這裏打開一個錯誤報告 - https://bitbucket.org/techtonik/python-pager/issues,以便它不會丟失。 –