Последовательный способ перенаправления stdin и stdout на файлы в python с использованием optparse
У меня есть дюжина программ, которые могут принимать входные данные через 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. Является ли это хорошим последовательным решением или я пропускаю что-то лучшее или более ожидаемое?
Ответы
Ответ 1
Для входных файлов вы можете использовать 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
Ответ 2
Если вы можете использовать argparse
(то есть Python 2.7+), у него есть встроенная поддержка того, что вы хотите: прямо из argparse
doc
FileType
factory создает объекты, которые могут быть переданы аргументу типа ArgumentParser.add_argument()
. Аргументы, которые имеют объекты FileType
как их тип, будут открывать аргументы командной строки [...] FileType
объекты понимают псевдо-аргумент "-" и автоматически преобразуют его в sys.stdin для читаемых объектов FileType
и sys.stdout
для записываемые объекты FileType
.
Поэтому мой совет - просто использовать
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