Подтвердить что ты не робот

Как читать из stdin или из файла, если в Python нет данных?

У меня CLI script и хочу, чтобы он считывал данные из файла. Он должен иметь возможность читать его двумя способами:

  • cat data.txt | ./my_script.py
  • ./my_script.py data.txt

- бит, например, grep.

Что я знаю:

  • sys.argv и optparse позволяют мне легко читать любые аргументы и варианты.
  • sys.stdin Позвольте мне прочитать данные, отправленные в
  • fileinput сделать полный процесс автоматической

К сожалению:

  • Использование fileinput использует stdin и любые аргументы в качестве входных данных. Поэтому я не могу использовать параметры, которые не являются именами файлов, когда он пытается их открыть.
  • sys.stdin.readlines() работает нормально, но если я не обрабатываю какие-либо данные, он зависает, пока я не введу Ctrl + D
  • Я не знаю, как реализовать "если ничего в stdin, прочитайте из файла в args", потому что stdin всегда True в булевом контексте.

Я бы хотел, чтобы это было возможно, если это возможно.

4b9b3361

Ответ 1

Обработайте ваши аргументы без имени файла, но вы хотите, чтобы вы завершили массив аргументов без параметра, затем передайте этот массив в качестве параметра fileinput.input():

import fileinput
for line in fileinput.input(remaining_args):
    process(line)

Ответ 2

Argparse позволяет сделать это довольно легко, и вы действительно должны использовать его вместо optparse, если только вы имеют проблемы с совместимостью.

Код будет выглядеть примерно так:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--input', type = argparse.FileType('r'), default = '-')

Теперь у вас есть синтаксический анализатор, который будет анализировать аргументы командной строки, использовать файл, если он видит его, или использовать стандартный ввод, если это не так.

Ответ 3

Для unix/linux вы можете определить, поступают ли данные, просматривая os.isatty(0)

$ date | python -c "import os;print os.isatty(0)"
False
$ python -c "import os;print os.isatty(0)"
True

Я не уверен, что для Windows есть эквивалент.

изменить Хорошо, я попробовал это с python2.6 на Windows XP

C:\Python26>echo "hello" | python.exe -c "import os;print os.isatty(0)"  
False

C:\Python26> python.exe -c "import os;print os.isatty(0)"  
True

Так что, возможно, это не все безнадежно для windows

Ответ 4

Нет надежного способа определить, подключен ли sys.stdin к чему-либо, и не подходит ли это (например, пользователь хочет вставить данные). Определите наличие имени файла в качестве аргумента и используйте stdin, если он не найден.

Ответ 5

Я noob, так что это может быть не очень хороший ответ, но я пытаюсь сделать то же самое (разрешить один или несколько файлов в командной строке, по умолчанию для STDIN).

Последняя комбо я собрал:

parser = argparse.ArgumentParser()
parser.add_argument("infiles", nargs="*")
args = parser.parse_args()

for line in fileinput.input(args.infiles):
    process(line)

Это похоже на единственный способ получить все желаемое поведение в одном элегантном пакете, не требуя именных аргументов. Так же, как и команды unix, используются как таковые:

cat file1 file2
wc -l < file1

Не:

cat --file file1 --file file2

По достоинству оцените отзывы/подтверждение от ветеранов-идиоматических Pythonistas, чтобы убедиться, что у меня есть лучший ответ. Не видели этого полного решения, упомянутого где-то еще, только фрагменты.

Ответ 6

Вы можете использовать эту функцию, чтобы определить, является ли вход из конвейера или нет.

sys.stdin.isatty()

Он возвращает значение false, если вход от конвейера или true в противном случае.