Вывод интерактивного скрипта Python хранится в каком-то файле - PullRequest
1 голос
/ 20 декабря 2009

Как выполнить ведение журнала всех действий, выполняемых скриптом Python, и всех скриптов, которые вызываются из него?

У меня было несколько скриптов Bash, но теперь я написал скрипт Python, который вызывает все эти скрипты Bash. Я хотел бы, чтобы весь вывод, полученный из этих скриптов, хранился в каком-то файле.

Скрипт представляет собой интерактивный скрипт Python, то есть содержит строки raw_input, поэтому я не мог сделать что-то вроде 'python script.py | tee log.txt 'для всего скрипта Python, так как по некоторым причинам вопросы не видны на экране.

Вот выдержка из сценария, который вызывает один из сценариев оболочки.

    cmd = "somescript.sh"
    try:
    retvalue = subprocess.check_call(cmd, shell=True)
except subprocess.CalledProcessError:
    print ("script command has been failed")
    sys.exit("exit from script")

Как вы думаете, что здесь можно сделать?

Редактировать

Два подвопроса основаны на ответе Алекса:

  1. Как составить ответы и на вопросы, хранящиеся в выходном файле? Например, в строке ok = raw_input(prompt) пользователю будет задан вопрос, и я хотел бы, чтобы ответ также был зарегистрирован.

  2. Я читал о Попене, общался и не пользовался, поскольку он буферизует данные в памяти. Здесь объем вывода велик, и мне нужно заботиться о стандартной ошибке со стандартным выводом. Знаете ли вы, если это возможно, чтобы справиться с Popen и метод связи, а также?

Ответы [ 3 ]

7 голосов
/ 21 декабря 2009

Создание собственных Python print s для терминала и файла не сложно:

>>> import sys
>>> class tee(object):
...   def __init__(self, fn='/tmp/foo.txt'):
...     self.o = sys.stdout
...     self.f = open(fn, 'w')
...   def write(self, s):
...     self.o.write(s)
...     self.f.write(s)
... 
>>> sys.stdout = tee()
>>> print('hello world!')
hello world!
>>> 
$ cat /tmp/foo.txt
hello world!

Это должно работать как в Python 2, так и в Python 3.

Для аналогичного направления вывода из подкоманд не используйте

retvalue = subprocess.check_call(cmd, shell=True)

, который позволяет выводу cmd перейти к его обычному "стандартному выводу", но лучше взять и переиздать его самостоятельно, как показано ниже:

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
so, se = p.communicate()
print(so)
retvalue = p.returncode

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

Редактировать : ОП теперь уточнил спецификации в длинном комментарии к этому ответу:

  • Как сделать ответы на вопросы хранятся в выходном файле также? Например, в строке ок = raw_input (подскажите) пользователь будет задал вопрос, и я бы как и к ответу в журнале.

Используйте такую ​​функцию, как:

def echoed_input(prompt):
    response = raw_input(prompt)
    sys.stdout.f.write(response)
    return response

вместо просто raw_input в коде вашего приложения (конечно, это написано специально для взаимодействия с классом tee, который я показал выше).

  • Я читаю о Попене и общаюсь и не использовал, так как он буферизует данные в памяти. Здесь количество продукции большой, и мне нужно заботиться о стандартная ошибка со стандартным выходом также. Знаете ли вы, если это можно справиться с Попеном и а метод связи тоже?

communicate хорошо, если вы не получаете больше выходных данных (и стандартных ошибок), чем удобно помещается в памяти, скажем, не более нескольких гигабайт в зависимости от типа вашей машины повторное использование.

Если эта гипотеза будет соблюдена, просто перекодируйте вышеприведенное как:

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, 
                     stderr=subprocess.STDOUT)
so, se = p.communicate()
print(so)
retvalue = p.returncode

Т.е. просто перенаправьте stderr подкоманды, чтобы смешаться с ее stdout.

Если вам действительно нужно беспокоиться о гигабайтах (или что-то еще), приходящих на вас, то

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, 
                     stderr=subprocess.STDOUT)
for line in p.stdout:
  sys.stdout.write(p)
p.wait()
retvalue = p.returncode

(который получает и выдает по одной строке за раз) может быть предпочтительным (это зависит от cmd, не ожидающего ничего от своего стандартного ввода , конечно ... потому что, если оно ожидает чего-то, оно не получит его, и проблема начинает становиться сложной; -).

1 голос
/ 21 декабря 2009

Если вы хотите захватить вывод любого скрипта, то в * nix-y системе вы можете перенаправить stdout и stderr в файл:

./script.py >> /tmp/outputs.txt 2>> /tmp/outputs.txt

Если вы хотите, чтобы все выполнялось сценариями, а не только то, что они печатают, тогда модуль трассировки python не будет отслеживать действия внешних сценариев, которые выполняет ваш python. Единственное, что может отследить каждое действие, выполненное программой, это что-то вроде DTrace , если вам повезет иметь систему, которая поддерживает его. (Инструменты OS X основаны на DTrace)

1 голос
/ 20 декабря 2009

Python имеет модуль трассировки: trace . Использование: python -m trace --trace file.py

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...