Как заменить аргументы командной строки sys.argv на stdin stdout?

Я понимаю, что мой вопрос очень простой, но я не могу найти явного примера реализации stdin stdout в скрипте Python.

У меня есть скрипт, отлично работающий с аргументами командной строки:

newlist = []
def f1()
  .... 
def f2(input_file):
  vol_id = sys.argv[3]
  for line in input_file:
      if ... :
        line = line.replace('abc','def')
        line = line.replace('id', 'id'+vol_id)
      ....
      newlist.append(line)
   return newlist

def main():
    if len(sys.argv) < 4:
       print 'usage: ./myscript.py [file_in... file_out... volume_id]'
       sys.exit(1)

    else:

        filename = sys.argv[1]
        filename_out = sys.argv[2]


        tree = etree.parse(filename)
        extract(tree)

        input_file = open(filename, 'rU')
        change_class(input_file)

        file_new = open(filename_out, 'w')
        for x in newlist:

            if '\n' in x:                   
               x = x.replace('\n', '')                
            print>>file_new, x

Теперь я должен каким-то образом использовать stdin и stdout вместо моих аргументов, чтобы мой скрипт можно было использовать в конвейерах, например, используя несколько файлов в качестве входных данных:

кошка ввод1 ввод1 ввод3 | myscript.py

Или обработать его вывод с помощью некоторых инструментов UNIX перед его печатью в файл. Я попытался заменить аргументы в своем скрипте на sys.stdin:

filename = sys.stdin
filename_out = sys.stdout

Затем я запустил свой скрипт следующим образом:

./myscript.py ‹ входной файл > выходной файл

Это привело к пустому выходному файлу, но вообще не выдало никаких сообщений об ошибках.

Не могли бы вы помочь мне с этой заменой?

P.S. Затем я изменил свой main() следующим образом:

filename = sys.argv[1]
filename_out = sys.argv[2]

if filename == '-':
   filename = sys.stdin
else:
    input_file = open(filename, 'rU')


if filename_out == '-':
    filename_out = sys.stdout
    file_new = filename_out
else:
    file_new = open(filename_out, 'w')


tree = etree.parse(filename)
extract(tree)

input_file = filename
change_class(input_file)

for x in newlist:

    if '\n' in x:                   
       x = x.replace('\n', '')                
    print>>file_new, x

Я попытался запустить его из командной строки следующим образом:

./myscript.py - - volumeid < filein > fileout

Но у меня все еще есть пустой выходной файл :(


person user3241376    schedule 20.02.2014    source источник
comment
Вам может пригодиться модуль fileinput (в стандартной библиотеке).   -  person cdarke    schedule 20.02.2014
comment
@cdarke: fileinput отлично подходит, когда у вас есть только входные файлы. Вам все равно придется вручную обрабатывать аргументы командной строки и явно передавать файлы, которые fileinput следует рассматривать как входные данные.   -  person Martijn Pieters    schedule 20.02.2014


Ответы (1)


Обычным заполнителем для stdin или stdout является -:

./myscript.py - - volumeid

а также:

if filename == '-':
    input_file = sys.stdin
else:
    input_file = open(filename, 'rU')

и т.п.

Кроме того, вы можете по умолчанию использовать filename и filename_out в -, когда имеется менее 3 аргументов командной строки. Вам следует рассмотреть возможность использования специального анализатора аргументов командной строки, такого как argparse, который может обрабатывать эти случаи за вас, в том числе по умолчанию использовать stdin и stdout, а также использовать -.

Кстати, я бы не стал использовать print для записи в файл; Я бы просто использовал:

file_new.write(x)

что также устраняет необходимость удалять символы новой строки.

Похоже, вы дважды читаете входной файл; один раз для анализа дерева XML, еще раз для вызова change_class() с открытым файловым объектом. Что вы там пытаетесь сделать? У вас возникнут проблемы с воспроизведением этого с помощью sys.stdin, поскольку вы не сможете перечитать данные из потока так, как вы можете это сделать из файла на диске.

Вам придется сначала прочитать все данные в память, затем проанализировать из них XML, а затем снова прочитать его для change_class(). Было бы лучше, если бы вы использовали для этого проанализированное XML-дерево, если это возможно (например, прочитайте файл только один раз, а затем используйте проанализированную структуру оттуда).

person Martijn Pieters    schedule 20.02.2014
comment
Комментарии — не лучшее место для публикации кода. Если последующий вопрос включает в себя нечто большее, чем небольшое уточнение, возможно, вместо этого необходимо задать новый вопрос. - person Martijn Pieters; 20.02.2014
comment
точно! вот почему я поставил свой код в качестве ответа ниже - person user3241376; 20.02.2014
comment
Ах, используйте ответы вместо фактических ответов только! - person Martijn Pieters; 20.02.2014
comment
а ответы с равным количеством голосов сортируются случайным образом, поэтому я увидел ваш ответ не "ниже", а "выше". - person Martijn Pieters; 20.02.2014
comment
ОК, вопрос изменен - person user3241376; 20.02.2014
comment
Я не вижу ничего явно неправильного в вашем коде; возможно, добавьте несколько утверждений print, чтобы убедиться, что ваши предположения верны. - person Martijn Pieters; 20.02.2014
comment
@elaine_blath: ах, нет, я вижу, что идет не так; здесь вы не можете «перечитать» стандартный ввод дважды. Вы читаете inputfile при анализе XML, затем читаете его снова для вызова change_class; что ты пытаешься там сделать? - person Martijn Pieters; 20.02.2014
comment
Еще я подумал, что это, вероятно, связано с тем, что я дважды использую один и тот же входной файл... Но с sys.argv это сработало... - person user3241376; 20.02.2014
comment
@elaine_blath: Это потому, что вы дважды открыли файл в своем коде (с вызовом etree.parse(), открывающим его для вас сначала, вы явно открываете его во второй раз после этого). - person Martijn Pieters; 20.02.2014
comment
Сначала я использую парсер XML в f1(), чтобы извлечь 3 списка определений, затем в f2() я сравниваю элементы в этих списках с исходным файлом и меняю в нем значения классов, в соответствии с моими 3 списками - person user3241376; 20.02.2014
comment
@elaine_blath: Тогда единственный вариант, который у вас есть, — сначала прочитать все данные из входного файла в строку, а затем повторно использовать эту строку как для синтаксического анализа, так и для сравнения (используя etree.fromstring() вместо etree.parse(), IIRC). - person Martijn Pieters; 20.02.2014
comment
Я внес эти изменения, теперь у меня другие проблемы - я изменю свой вопрос через минуту - person user3241376; 20.02.2014
comment
Пожалуйста, не надо. Вместо этого создайте новый вопрос; Stack Overflow не подходит для трансформирующих вопросов. - person Martijn Pieters; 20.02.2014
comment
Вот мой новый вопрос: stackoverflow.com/questions/21911323/ Надеюсь, вы тоже его изучите. - person user3241376; 20.02.2014