Выполнение команды и сохранение ее выходных данных в переменной

#python

#python

Вопрос:

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

  1 #!/usr/bin/python
  2 import subprocess
  3 
  4 subprocess.call("./pmm", shell=True)
  

Как бы я мог сохранить выходные данные pmm в переменной?

Ответ №1:

В Python 2.7 (и 3.1 или выше) вы можете использовать subprocess.check_output() . Пример из документации:

 >>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/nulln'
  

Ответ №2:

 p = subprocess.Popen(["./pmm"], shell=False, stdout=subprocess.PIPE)
output = p.stdout.read()
  

Комментарии:

1. Это может привести к взаимоблокировке, если процесс выдает много выходных данных. Используйте p.communicate() вместо p.stdout.read() . (Смотрите Документы — прокрутите немного вверх.)

2. это не имеет особого смысла, поскольку включено предупреждение о взаимоблокировке p.wait() (как будто при заполнении выходного буфера процесс будет ждать, пока в нем не освободится место, таким образом, мертвая блокировка, если процесс чтения ожидает его), не p.stdout.read() который, как p.communicate() , завершится неудачей, если выходные данные будут большими или неограниченными, и в этом случае было бы лучше читать порциями.

3. @Dan D: Предупреждение находится непосредственно над документацией Popen.stdout и гласит «Используйте communicate() вместо .stdin.write , .stdout.read или .stderr.read чтобы избежать взаимоблокировок […]».

4. Если подумать, это не приведет к тупиковой ситуации, если процесс выдает много выходных данных в stdout , а скорее, если в stderr много выходных данных для заполнения буфера файлового дескриптора, который не читается.

5. да, но если вы не записываете в p.stdin , а только читаете из p.stdout , взаимоблокировки быть не может.

Ответ №3:

Я написал сообщение об этом некоторое время назад:

http://trifoliummedium.blogspot.com/2010/12/running-command-line-with-python-and.html

Используйте p.communicate(), чтобы получить как stdout, так и stderr

Ответ №4:

Сначала вы должны сохранить ссылку на подпроцесс (привязать его к имени … что на других языках и более неформально называется «присвоение ее переменной»). Итак, вы должны использовать что-то вроде proc = subprocess.Popen(...)

Оттуда я рекомендую вам вызвать proc.poll() , чтобы проверить, завершилась ли программа, и либо перейти в режим ожидания (например, используя time.sleep() функцию), либо выполнить другую работу (например, используя select.select() ), а затем проверить еще раз, позже. Или вы можете вызвать proc.wait() , чтобы убедиться, что команда this ./pmm завершила свою работу, прежде чем ваша программа продолжит. poll() Метод экземпляра подпроцесса вернет «None», если подпроцесс все еще запущен; в противном случае он вернет значение завершения команды, которая выполнялась в этом подпроцессе. wait() Метод для подпроцесса приведет к блокировке вашей программы, а затем вернет значение exit.

После этого вы можете вызвать (output, errormsgs) = proc.communicate() для захвата любых выходных данных или сообщений об ошибках из вашего подпроцесса. Если выходные данные слишком велики, это может вызвать проблемы; использование экземпляра процесса .stdout (дескриптор файла канала) сложно, и, если вы собираетесь попробовать это, вам следует использовать функции в fcntl модуле (управление файловыми дескрипторами), чтобы переключить его в неблокирующий режим и быть готовым обрабатывать исключения, возникающие при попытке read() вызвать буфер, когда он пуст.

Комментарии:

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