2009-11-16 93 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