Чтение из файла или STDIN
Я написал утилиту командной строки, которая использует getopt для анализа аргументов, заданных в командной строке. Я также хотел бы, чтобы имя файла было необязательным аргументом, например, в других утилитах, таких как grep, cut и т.д. Поэтому я хотел бы иметь следующее использование
tool -d character -f integer [filename]
Как я могу реализовать следующее?
- Если задано имя файла, прочитайте его из файла.
- если имя файла не указано, прочитайте из STDIN.
Ответы
Ответ 1
В простейших терминах:
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
Модуль fileinput может делать то, что вы хотите - если аргументы без параметра находятся в args
, то:
import fileinput
for line in fileinput.input(args):
print line
Если args
пусто, тогда fileinput.input()
будет читать из stdin; в противном случае он читает из каждого файла по очереди, аналогично Perl while(<>)
.
Ответ 3
Мне нравится общая идиома использования диспетчера контекста, но (слишком) тривиальное решение заканчивается закрытием sys.stdin
, когда вы находитесь вне инструкции with
, которую я хочу избежать.
Заимствование из этого ответа, это обходное решение:
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)
Я полагаю, вы могли бы достичь чего-то подобного с os.dup()
, но код, который я приготовил для этого, оказался более сложным и более волшебным, тогда как выше является несколько неуклюжим, но очень простым.
Ответ 4
Чтобы использовать оператор python with
, можно использовать следующий код:
import sys
with open(sys.argv[1], 'r') if len(sys.argv) > 1 else sys.stdin as f:
# read data using f
# ......
Ответ 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
Ответ 6
Что-то вроде:
if input_from_file:
f = open(file_name, "rt")
else:
f = sys.stdin
inL = f.readline()
while inL:
print inL.rstrip()
inL = f.readline()