在Python中使用optparse一致地重定向stdin和stdout到文件

14 投票
2 回答
7358 浏览
提问于 2025-04-17 04:50

我有一堆程序,可以通过标准输入(stdin)或者选项来接收输入,现在我想用类似的方式来处理输出。

optparse的代码看起来是这样的:

parser.add_option('-f', '--file',
       default='-',
       help='Specifies the input file.  The default is stdin.')
parser.add_option('-o', '--output',
       default='-',
       help='Specifies the output file.  The default is stdout.')

其他相关的代码是这样的:

if opts.filename == '-':
    infile = sys.stdin
else:
    infile = open(opts.filename, "r")

if opts.output == '-':
    outfile = sys.stdout
else:
    outfile = open(opts.output, "w")

这段代码运行得很好,我喜欢它的简单性——但我找不到有人使用默认值'-'来表示输出到标准输出(stdout)的参考资料。这样做是个好方法吗?还是我忽略了什么更好或者更常见的做法?

2 个回答

12

如果你能使用 argparse(也就是 Python 2.7 及以上版本),它就有内置的功能可以满足你的需求:直接来自 argparse 文档

FileType 工厂可以创建一些对象,这些对象可以传递给 ArgumentParser.add_argument() 的类型参数。那些类型为 FileType 的参数会打开命令行参数 […] FileType 对象能够理解伪参数 '-',并会自动把它转换为可读的 sys.stdin 和可写的 sys.stdout

所以我的建议就是直接使用

import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('file', type=argparse.FileType('r'),
    help="Specifies the input file")
parser.add_argument('output', type=argparse.FileType('w'),
    help="Specifies the output file")
args = parser.parse_args(sys.argv[1:])

# Here you can use your files
text = args.file.read()
args.output.write(text)
# … and so on

这样你就可以做到

> python spam.py file output 

file 读取并输出到 output,或者

> echo "Ni!" | python spam.py - output  

读取 "Ni!" 并输出到 output,或者

> python spam.py file -

这样做很好,因为在相关流中使用 - 是很多程序都遵循的一个约定 。如果你想强调这一点,可以把它加到 help 字符串中。

  parser.add_argument('file', type=argparse.FileType('r'),
    help="Specifies the input file, '-' for standard input")

作为参考,使用说明信息将会是

> python spam.py -h
usage: [-h] file output

positional arguments:
  file        Specifies the input file, '-' for standard input
  output      Specifies the output file, '-' for standard output

optional arguments:
  -h, --help  show this help message and exit
15

对于输入文件,你可以使用fileinput模块。这个模块遵循了一个常见的规则:如果没有提供文件名或者文件名是'-',它就会从标准输入(stdin)读取数据;如果提供了文件名,它就会从命令行中指定的文件读取。

其实不需要使用-f--file这些选项。如果你的程序总是需要一个输入文件,那就不算是一个可选项。

-o--output是用来指定输出文件名的选项,在不同的程序中都可以用到。

optparse

#!/usr/bin/env python
import fileinput
import sys
from optparse import OptionParser

parser = OptionParser()
parser.add_option('-o', '--output',
    help='Specifies the output file.  The default is stdout.')
options, files = parser.parse_args()
if options.output and options.output != '-':
   sys.stdout = open(options.output, 'w')

for line in fileinput.input(files):
    process(line)

argparse

argparse模块允许你明确地将文件作为参数指定:

#!/usr/bin/env python
import fileinput
import sys
from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument('files', nargs='*', help='specify input files')
group = parser.add_mutually_exclusive_group()
group.add_argument('-o', '--output', 
    help='specify the output file.  The default is stdout')
group.add_argument('-i', '--inplace', action='store_true',
    help='modify files inplace')
args = parser.parse_args()

if args.output and args.output != '-':
   sys.stdout = open(args.output, 'w')

for line in fileinput.input(args.files, inplace=args.inplace):
    process(line)

注意:在第二个例子中,我添加了--inplace选项:

$ python util-argparse.py --help
usage: util-argparse.py [-h] [-o OUTPUT | -i] [files [files ...]]

positional arguments:
  files                 specify input files

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        specify the output file. The default is stdout
  -i, --inplace         modify files inplace

撰写回答