2009-11-16 127 views
49

我已經編寫了一個命令行實用程序,它使用getopt來解析命令行中給出的參數。我也想有一個文件名是一個可選的參數,如它在其他實用程序,如grep,剪切等,所以,我想它有以下用途從文件讀取或STDIN

tool -d character -f integer [filename] 

我如何能實現以下?

  • 如果給出文件名,則從文件中讀取。
  • 如果沒有給出文件名,則從STDIN中讀取。
+2

另請參閱http://unix.stackexchange.com/questions/47098/how-do-i-make-python-programs-behave-like-proper-unix-tools/47543#47543 – magnetar 2012-09-08 12:18:22

回答

47

簡單的說:

import sys 
# parse command line 
if file_name_given: 
    inf = open(file_name_given) 
else: 
    inf = sys.stdin 

此時你會使用inf從文件中讀取。根據是否給出文件名,這將從給定文件或標準輸入讀取。

當您需要關閉文件,你可以這樣做:

if inf is not sys.stdin: 
    inf.close() 

然而,在大多數情況下,它是無害關閉sys.stdin,如果你用它做。

+0

raw_input()和input()會從inf中讀取嗎? – thefourtheye 2013-05-03 12:54:23

+0

@thefourtheye:是的,這兩個函數都會從文件或sys.stdin中讀取。 – 2013-05-03 18:41:26

+2

我發現了另一種解決這個問題的方法,我在http://dfourtheye.blogspot.in/2013/05/python-equivalent-of-cs-freopen.html這裏發佈了博客,並且也爲這個問題添加了一個答案。 – thefourtheye 2013-05-04 02:16:48

61

fileinput模塊可以做你想做的 - 假設非選項參數是args則:

import fileinput 
for line in fileinput.input(args): 
    print line 

如果args爲空,則fileinput.input()會從標準輸入讀取;否則它會依次讀取每個文件,與Perl的while(<>)類似。

+0

這也一樣好的答案,但不是一般的。如果適用,我會記得下次使用fileinput。 – 2009-11-30 22:47:08

+0

它也可以不用'args'。 – Gabriel 2015-02-18 03:53:25

+0

沒錯,但是如果你使用'getargs'(因爲OP是),那麼你可能只想傳遞剩下的args而不是'sys.argv [1:]'(這是默認值)。 – SimonJ 2015-03-07 22:51:33

0

喜歡的東西:

if input_from_file: 
    f = open(file_name, "rt") 
else: 
    f = sys.stdin 
inL = f.readline() 
while inL: 
    print inL.rstrip() 
    inL = f.readline() 
8

要使用Python的with語句,可以使用下面的代碼:

import sys 
with open(sys.argv[1], 'r') if len(sys.argv) > 1 else sys.stdin as f: 
    # read data using f 
    # ...... 
+0

您的解決方案將關閉'sys.stdin',因此在'with'語句之後調用'input'函數會引發'ValueError'。 – 2015-05-24 15:42:32

5

我更願意用「 - 」爲你應該閱讀的指標從stdin,它更明確:

import sys 
with open(sys.argv[1], 'r') if sys.argv[1] is not "-" else sys.stdin as f: 
    pass # do something here 
+2

您的解決方案將關閉'sys.stdin',因此在'with'語句之後調用'input'函數會引發'ValueError'。 – 2015-05-24 15:42:27

+1

@TimofeyBondarev這可能是正確的..但最常見的輸入只在腳本中使用一次。這是一個有用的構造。 – javadba 2016-02-02 05:52:44

11

我喜歡使用上下文管理的一般習語呃,但是當你不在我想要避免的with聲明中時,(太)無效的解決方案最終會結束sys.stdin

this answer借款,這裏是一個解決辦法:

import sys 
import contextlib 

@contextlib.contextmanager 
def _smart_open(filename, mode='Ur'): 
    if filename == '-': 
     if mode is None or mode == '' or 'r' in mode: 
      fh = sys.stdin 
     else: 
      fh = sys.stdout 
    else: 
     fh = open(filename, mode) 
    try: 
     yield fh 
    finally: 
     if filename is not '-': 
      fh.close() 

if __name__ == '__main__': 
    args = sys.argv[1:] 
    if args == []: 
     args = ['-'] 
    for filearg in args: 
     with _smart_open(filearg) as handle: 
      do_stuff(handle) 

我想你可以實現something similar with os.dup(),但我做了這樣做竟然是更復雜,更神奇的代碼,而上面是有點笨重但很直接。

+0

非常感謝!這正是我正在尋找的。非常明確和直接的解決方案。 – edisonex 2017-11-15 13:43:20