从文件或STDIN中读取

时间:2009-11-16 21:32:23

标签: python file command-line arguments stdin

我编写了一个命令行实用程序,它使用getopt来解析命令行中给出的参数。我也希望有一个文件名是一个可选参数,比如它在其他实用程序中,如grep,cut等。所以,我希望它具有以下用法

tool -d character -f integer [filename]

如何实施以下内容?

  • 如果给出了文件名,请从文件中读取。
  • 如果没有给出文件名,请从STDIN读取。

8 个答案:

答案 0 :(得分:72)

fileinput模块可以做你想要的 - 假设非选项参数在args中,那么:

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

如果args为空,则fileinput.input()将从标准输入读取;否则它会以与Perl的while(<>)类似的方式依次从每个文件中读取。

答案 1 :(得分:56)

用最简单的术语来说:

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

此时,您将使用inf从文件中读取。根据是否给出文件名,这将从给定文件或stdin中读取。

当您需要关闭文件时,您可以执行以下操作:

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

但是,在大多数情况下,如果您已完成此操作,则关闭sys.stdin将无害。

答案 2 :(得分:15)

我喜欢使用上下文管理器的一般习惯用法,但是当你离开我想避免的sys.stdin语句时,(太)琐碎的解决方案最终会关闭with

借用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()但是我做的那些代码变得更复杂,更神奇,而上面的内容有点笨拙而且非常简单。

答案 3 :(得分:10)

要使用python的with语句,可以使用以下代码:

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

答案 4 :(得分:9)

我更喜欢使用“ - ”作为你应该从stdin读取的指标,它更明确:

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

答案 5 :(得分:5)

不是直接的答案,而是相关的。

通常在编写python脚本时可以使用argparse包。 如果是这种情况,您可以使用:

parser = argparse.ArgumentParser()
parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
  

&#39;&#39 ;.如果可能,将从命令行使用一个参数,   并作为单个项目生产。如果不存在命令行参数,   将生成默认值。

这里我们将默认设置为sys.stdin;

所以如果有一个文件它将读取它,如果没有它将从stdin&#34获取输入;注意:我们在上面的例子中使用位置参数&#34;

更多访问:https://docs.python.org/2/library/argparse.html#nargs

答案 6 :(得分:1)

类似的东西:

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

答案 7 :(得分:0)

切换到argparse(它也是标准库的一部分)并使用 argparse.FileType,默认值为stdin:

import  argparse, sys

p = argparse.ArgumentParser()
p.add_argument('input', nargs='?',
  type=argparse.FileType(), default=sys.stdin)
args = p.parse_args()

print(args.input.readlines())

这将不允许您为stdin指定编码和其他参数, 然而;如果要这样做,则需要使参数为非可选 并将FileType设置为{ 参数:

-

请注意,后一种情况将不支持二进制模式(p.add_argument('input', type=FileType(encoding='UTF-8')) )I / O。如果 您只需要 即可使用上面的默认参数技术,但是 提取二进制I / O对象,例如'b' 标准输出。但是,如果用户仍然指定default=sys.stdout.buffer,这仍然会中断。 (对于-,stdin / stdout始终包裹在-中。)

如果您希望它与TextIOWrapper一起使用,或者需要任何其他参数, 在打开文件时提供,如果文件被包裹,则可以修复该参数 错误:

-

medhat的提示) 提到p.add_argument('output', type=argparse.FileType('wb')) args = p.parse_args() if hasattr(args.output, 'buffer'): # If the argument was '-', FileType('wb') ignores the 'b' when # wrapping stdout. Fix that by grabbing the underlying binary writer. args.output = args.output.buffer 的{​​{1}}参数。)