Для запуска программ из моих Python-скриптов я использую следующий метод:
def execute(command):
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = process.communicate()[0]
exitCode = process.returncode
if (exitCode == 0):
return output
else:
raise ProcessException(command, exitCode, output)
Поэтому, когда я запускаю такой процесс Process.execute("mvn clean install")
, моя программа ждет, пока процесс не завершится, и только тогда я получаю полный вывод моей программы. Это раздражает, если я запускаю процесс, который занимает некоторое время, чтобы закончить.
Могу ли я позволить моей программе записывать вывод процесса построчно, опрашивая вывод процесса до его завершения в цикле или что-то еще?
** [РЕДАКТИРОВАТЬ] Извините, я не очень хорошо искать, прежде чем отправлять этот вопрос. Потоки на самом деле ключ. Здесь нашел пример, который показывает, как это сделать: ** Python Subprocess.Popen from the thread
python
subprocess
Инго Фишер
источник
источник
Ответы:
Вы можете использовать ITER для обработки строк , как только команда выводит их:
lines = iter(fd.readline, "")
. Вот полный пример, показывающий типичный вариант использования (спасибо @jfs за помощь):источник
for line in popen.stdout: print(line.decode(), end='')
. Для поддержки как Python 2, так и 3 используйте байтовый литерал: вb''
противном случае онlines_iterator
никогда не заканчивается на Python 3.bufsize=1
исправить это, вы можете добавить (это может улучшить производительность в Python 2),popen.stdout
явно закрыть канал (не дожидаясь, пока сборщик мусора позаботится об этом), и повыситьsubprocess.CalledProcessError
(напримерcheck_call()
,check_output()
сделать). Этоprint
утверждение отличается от Python 2 и 3: вы можете использовать хак софтспейсprint line,
(примечание: запятая), чтобы избежать удвоения всех новых строк, как это делает ваш код, и передачиuniversal_newlines=True
на Python 3, чтобы получить текст вместо байтового ответа .execute(["python", "-u", "child_thread.py"])
. Более подробная информация: stackoverflow.com/questions/14258500/...Хорошо, мне удалось решить это без потоков (любые предложения, почему использование потоков было бы лучше) с помощью фрагмента из этого вопроса Перехват stdout подпроцесса во время его работы
источник
print line,
вsys.stdout.write(nextline); sys.stdout.flush()
противном случае, он будет печатать каждые две строки , затем снова, это использует интерфейс ноутбука IPython, так что, может быть , еще что - то происходит -.. Несмотря на это , явно вызываяflush()
работы.stderr=subprocess.STDOUT
кstderr=subprocess.PIPE
и затем вызватьprocess.stderr.readline()
внутри цикла, я , кажется, прервала очень тупиковой , что предупрежден о в документации наsubprocess
модуль.stdout=subprocess.PIPE,stderr=subprocess.STDOUT
это захватывает stderr, и я верю (но я не проверял), что он также захватывает stdin.Чтобы выводить вывод подпроцесса построчно, как только его буфер stdout будет очищен в Python 3:
Обратите внимание: вам не нужно
p.poll()
- цикл заканчивается, когда достигается eof. И вам это не нужноiter(p.stdout.readline, '')
- ошибка опережающего чтения исправлена в Python 3.Смотрите также, Python: чтение потокового ввода из subprocess.communicate () .
источник
sys.stdout.flush()
в родительском элементе - stdout буферизуется строкой, если он не перенаправлен в файл / канал и, следовательно, печатьline
очищает буфер автоматически. Вам тоже не нуженsys.stdout.flush()
ребенок --u
вместо этого передайте опцию командной строки.>
запуститеpython -u your-script.py > some-file
. Обратите внимание:-u
вариант, который я упомянул выше (не нужно использоватьsys.stdout.flush()
).p.wait()
- он вызывается при выходе изwith
блока. Использованиеp.returncode
.На самом деле существует действительно простой способ сделать это, когда вы просто хотите напечатать вывод:
Здесь мы просто указываем подпроцесс на наш собственный stdout и используем существующие API-интерфейсы success или исключений.
источник
shell=True
@tokland
попробовал ваш код и исправил его для 3.4 и windows dir.cmd - простая команда dir, сохраненная как cmd-файл
источник
iter()
иend='\r\n'
не нужны. Python по умолчанию использует универсальный режим перевода строки, то есть любой'\n'
переводится во'\r\n'
время печати.'latin'
Возможно, это неправильная кодировка, вы можете использовать ееuniversal_newlines=True
для вывода текста в Python 3 (декодируется с использованием предпочтительной кодировки локали). Не останавливайтесь.poll()
, там могут быть буферизованные непрочитанные данные. Если скрипт Python выполняется в консоли, то его вывод буферизуется в строке; Вы можете включить буферизацию строки, используя-u
опцию - вамflush=True
здесь не нужно .В случае, если кто-то хочет читать из обоих
stdout
иstderr
в то же время, используя потоки, это то, что я придумал:Я просто хотел поделиться этим, так как я закончил на этом вопросе, пытаясь сделать что-то подобное, но ни один из ответов не решил мою проблему. Надеюсь, это кому-нибудь поможет!
Обратите внимание, что в моем случае использования внешний процесс убивает процесс, который мы
Popen()
.источник
Для тех, кто пытается получить ответы на этот вопрос, чтобы получить стандартный вывод из скрипта Python, обратите внимание, что Python буферизует свой стандартный вывод, и поэтому для его просмотра может потребоваться некоторое время.
Это можно исправить, добавив следующее после каждой записи stdout в целевой скрипт:
источник
import
другой сценарий; посмотритеmultiprocessing
илиthreading
если вам нужно распараллеленное выполнение.subprocess.run("/path/to/python/executable", "pythonProgramToRun.py")
В Python> = 3.5 использование
subprocess.run
работает для меня:(получение вывода во время выполнения также работает без
shell=True
) https://docs.python.org/3/library/subprocess.html#subprocess.runисточник
subprocess.run()
Вызов возвращает только тогда , когда подпроцесс закончит работу.>>> import subprocess; subprocess.run('top')
также, похоже, печатается «во время выполнения» (а top никогда не заканчивается). Может я не уловил какой-то тонкой разницы?stdout=subprocess.PIPE
вы можете прочитать его только послеtop
завершения. Ваша программа Python заблокирована во время выполнения подпроцесса.run
Метод все еще работает , если вы заинтересованы только в видя выхода , как это генерируется. Если вы хотите что-то сделать с выводом в python асинхронно, вы правы, что это не работает.Чтобы ответить на исходный вопрос, лучшим способом IMO является просто перенаправление подпроцесса
stdout
непосредственно на вашу программуstdout
(опционально, то же самое можно сделать дляstderr
, как в примере ниже)источник
stdout
иstderr
делает то же самое с меньшим количеством кода. Хотя я полагаю, что явное лучше, чем неявное.Этот PoC постоянно читает выходные данные процесса и может быть доступен при необходимости. Сохраняется только последний результат, все остальные выходные данные отбрасываются, что препятствует росту памяти PIPE:
print_date.py
Вывод: вы можете ясно видеть, что между интервалом ~ 2,5 с ничего нет.
источник
Это работает по крайней мере в Python3.4
источник
Ни один из ответов здесь не отвечает всем моим потребностям.
Немного предыстории: я использую ThreadPoolExecutor для управления пулом потоков, каждый из которых запускает подпроцесс и выполняет их параллелизм. (В Python2.7, но это должно работать и в более новых 3.x). Я не хочу использовать потоки только для сбора выходных данных, так как хочу, чтобы как можно больше было доступно для других целей (пул из 20 процессов использовал бы только 40 потоков для запуска; 1 для потока процесса и 1 для stdout ... и еще если хочешь стдерр наверное)
Я отбрасываю множество исключений и тому подобное здесь, так что это основано на коде, который работает в производстве. Надеюсь, я не испортил это в копии и вставке. Также, отзывы очень приветствуются!
Я уверен, что здесь добавляются накладные расходы, но в моем случае это не проблема. Функционально он делает то, что мне нужно. Единственное, что я не решил, - почему это прекрасно работает для сообщений журнала, но я вижу, что некоторые
print
сообщения появляются позже и все сразу.источник
В Python 3.6 я использовал это:
источник
subprocess.call()
имеет некоторые бородавки, которые исправляются новыми функциями; в Python 3.6 вы обычно используетеsubprocess.run()
для этого; для удобства более старая функция-оберткаsubprocess.check_output()
также по-прежнему доступна - она возвращает фактический вывод процесса (этот код будет возвращать только код завершения, но даже вместо этого вывести что-то неопределенное).