Читать из файла или STDIN - PullRequest
58 голосов
/ 17 ноября 2009

Я написал утилиту командной строки, которая использует getopt для анализа аргументов, заданных в командной строке. Я также хотел бы, чтобы имя файла было необязательным аргументом, например, в других утилитах, таких как grep, cut и т. Д. Итак, я бы хотел, чтобы оно имело следующий вид использования

tool -d character -f integer [filename]

Как я могу реализовать следующее?

  • если задано имя файла, читать из файла.
  • если имя файла не указано, читать из STDIN.

Ответы [ 7 ]

72 голосов
/ 17 ноября 2009

Модуль fileinput может делать то, что вы хотите - при условии, что аргументы без опций находятся в args, тогда:

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

Если args пусто, то fileinput.input()будет читать со стандартного ввода;в противном случае он читает из каждого файла по очереди, аналогично Perl while(<>).

57 голосов
/ 17 ноября 2009

Проще говоря:

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, если вы покончили с этим, будет безопасно.

16 голосов
/ 23 апреля 2015

Мне нравится общая идиома использования диспетчера контекста, но (слишком) тривиальное решение заканчивается закрытием 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(), но код, который я подготовил для этого, оказался более сложным и более волшебным, тогда как вышеприведенное несколько неуклюже, но очень просто.

11 голосов
/ 06 ноября 2013

Чтобы использовать оператор with в python, можно использовать следующий код:

import sys
with open(sys.argv[1], 'r') if len(sys.argv) > 1 else sys.stdin as f:
    # read data using f
    # ......
9 голосов
/ 26 января 2015

Я предпочитаю использовать «-» в качестве индикатора, который вы должны читать из стандартного ввода, это более явно:

import sys
with open(sys.argv[1], 'r') if sys.argv[1] is not "-" else sys.stdin as f:
    pass # do something here
5 голосов
/ 24 мая 2018

Не прямой ответ, но связанный.

Обычно, когда вы пишете скрипт на python, вы можете использовать пакет argparse. Если это так, вы можете использовать:

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

'?'. Один аргумент будет использован из командной строки, если это возможно, и производится как единое целое. Если аргумент командной строки отсутствует, будет получено значение по умолчанию.

и здесь мы устанавливаем значение по умолчанию sys.stdin;

так что если есть файл, он будет читать его, а если нет, он будет принимать входные данные из stdin «Примечание: мы используем позиционный аргумент в примере выше»

для дальнейшего посещения: https://docs.python.org/2/library/argparse.html#nargs

1 голос
/ 17 ноября 2009

Что-то вроде:

if input_from_file:
    f = open(file_name, "rt")
else:
    f = sys.stdin
inL = f.readline()
while inL:
    print inL.rstrip()
    inL = f.readline()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...