Как читать из 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
в булевом контексте.
Я бы хотел, чтобы это было возможно, если это возможно.
Ответы
Ответ 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 в противном случае.