- Python Subprocess Read Stdout While Running
- Python Subprocess Read stdout While Running
- Approach 1: Use check_call to Read stdout of a subprocess While Running in Python
- Approach 2: Poll the Process to Read stdout of a subprocess While Running in Python
- Related Article — Python Subprocess
- Модуль subprocess
Python Subprocess Read Stdout While Running
- Python Subprocess Read stdout While Running
- Approach 1: Use check_call to Read stdout of a subprocess While Running in Python
- Approach 2: Poll the Process to Read stdout of a subprocess While Running in Python
The main aim of this article is to demonstrate how to read the stdout of a subprocess being executed in Python.
Python Subprocess Read stdout While Running
As with many other built-in modules, Subprocess is also a built-in module that comes pre-installed with a “normal” Python installation.
It is used mostly when you want to run tasks, processes, and programs in a new process, perform a specific set of tasks and return the result.
One of its many reasons for wide usage is that it allows the execution of external programs and executables right from the program as a separate process.
While executing a program using the Subprocess library, it may be required that the output of that external program be shown in real-time. This can be a requirement for plenty of reasons, such as when a program may be real-time and depends on calculations after a short amount of time.
Consider the following program:
import subprocess 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 Exception(command, exitCode, output) if __name__ == '__main__': print(execute("cd C:\\ && C: && tree").decode('unicode_escape'))
Folder PATH listing Volume serial number is 0213-B7F2 C:. +---DRIVERS ¦ +---bluetooth ¦ +---U1BLT07AVVASDSAP ¦ +---Custom ¦ ¦ +---EULA ¦ +---Win64 ¦ +---LD ¦ +---svcpack +---flutter ¦ +---.git ¦ ¦ +---hooks ¦ ¦ +---info ¦ ¦ +---logs ¦ ¦ ¦ +---refs ¦ ¦ ¦ +---heads ¦ ¦ ¦ +---remotes ¦ ¦ ¦ +---origin ¦ ¦ +---objects ¦ ¦ ¦ +---info ¦ ¦ ¦ +---pack ¦ ¦ +---refs ¦ ¦ +---heads ¦ ¦ +---remotes ¦ ¦ ¦ +---origin ¦ ¦ +---tags ¦ +---.github ¦ ¦ +---ISSUE_TEMPLATE ¦ ¦ +---workflows ¦ +---.idea ¦ ¦ +---runConfigurations .
We can see the output in the program but not in real-time. The output will only be shown after the whole command ( tree in our case) has finished executing.
The output will not show something until the program (or command) is executed in a separate process using the Subprocess command.
In our case, since it is required that we should get the output in real-time, we need to create another solution, the one which shows the output of the program as it is written to the stdout .
The solution can be approached in multiple ways, some of which are mentioned below.
Approach 1: Use check_call to Read stdout of a subprocess While Running in Python
Consider the following code:
import subprocess import sys def execute(command): subprocess.check_call(command, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT) if __name__ == '__main__': print(execute("cd C:\\ && C: && tree").decode('unicode_escape'))
Folder PATH listing Volume serial number is 0213-B7F2 C:. ├───DRIVERS │ └───bluetooth │ └───U1BLT0720US14CMP │ ├───Custom │ │ └───EULA │ └───Win64 │ ├───LD │ └───svcpack ├───flutter │ ├───.git │ │ ├───hooks │ │ ├───info │ │ ├───logs │ │ │ └───refs │ │ │ ├───heads │ │ │ └───remotes │ │ │ └───origin │ │ ├───objects │ │ │ ├───info │ │ │ └───pack │ │ └───refs │ │ ├───heads │ │ ├───remotes │ │ │ └───origin │ │ └───tags │ ├───.github │ │ ├───ISSUE_TEMPLATE │ │ └───workflows │ ├───.idea │ │ └───runConfigurations │ ├───.pub-cache │ │ ├───hosted │ │ │ └───pub.dartlang.org │ │ │ ├───.cache .
If the main requirement is to print the program’s output in real-time, check_call can be used to achieve this. This simple, clean and elegant solution is concise and “just perfect” for very simple programs, like when only the output needs to be printed.
The check_call also supports passing parameters, so if your program needs any arguments to work, they can be passed easily to the function without any hassle. This method waits for the program to complete.
Based on the completion of the program, the method returns; otherwise, it raises a CalledProcessError exception. The CalledProcessError will have the failure return code, which can be accessed using the returncode attribute.
In the code mentioned above, the command is passed to the check_call method, which contains the command (or the program) to be executed.
The shell parameter was set to true to execute the process using a shell, and the process’ stdout is set to the stdout of our program, so it writes directly to our stdout , and we can see the changes as they happen in our stdout .
Lastly, the stderr is set to the stdout of the spawned process.
Approach 2: Poll the Process to Read stdout of a subprocess While Running in Python
Consider the following code:
import subprocess import sys def execute(command): process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Poll process for new output until finished while True: nextline = process.stdout.readline().decode('unicode_escape') if nextline == '' and process.poll() is not None: break sys.stdout.write(nextline) sys.stdout.flush() output = process.communicate()[0] exitCode = process.returncode if (exitCode == 0): return output else: raise Exception(command, exitCode, output) if __name__ == '__main__': print(execute("cd C:\\ && C: && tree").decode('unicode_escape'))
. ¦ ¦ ¦ ¦ ¦ +---UuidUtil ¦ ¦ ¦ ¦ +---example ¦ ¦ ¦ ¦ +---lib ¦ ¦ ¦ ¦ +---test ¦ ¦ ¦ +---vector_math-2.1.2 ¦ ¦ ¦ ¦ +---benchmark ¦ ¦ ¦ ¦ +---bin ¦ ¦ ¦ ¦ +---lib ¦ ¦ ¦ ¦ ¦ +---src ¦ ¦ ¦ ¦ ¦ +---vector_math ¦ ¦ ¦ ¦ ¦ ¦ +---third_party ¦ ¦ ¦ ¦ ¦ +---vector_math_64 ¦ ¦ ¦ ¦ ¦ ¦ +---third_party ¦ ¦ ¦ ¦ ¦ +---vector_math_geometry ¦ ¦ ¦ ¦ ¦ ¦ +---filters ¦ ¦ ¦ ¦ ¦ ¦ +---generators ¦ ¦ ¦ ¦ ¦ +---vector_math_lists ¦ ¦ ¦ ¦ ¦ +---vector_math_operations ¦ ¦ ¦ ¦ +---test ¦ ¦ ¦ ¦ +---tool ¦ ¦ ¦ +---video_player-2.2.11 ¦ ¦ ¦ ¦ +---android ¦ ¦ ¦ ¦ ¦ +---gradle .
To ensure that the program’s output spawned using the Subprocess is printed as soon as it is written to the stdout , we need to poll the process for output and continue reading the last line of the stdout of the program’s stdout .
In an “infinite” loop, we continue to read the output of the spawned process using readline() . Since the output is encoded, we need to decode it ( utf-escape in our case) to be represented suitably.
This can be done using the decode method and passing the relevant encoding scheme.
This can be done quite simply, with a simple string comparison for the first condition and the poll() method to check if the process has terminated or not. If the program has terminated, it returns the returncode ; otherwise, it returns None .
A simple comparison with None can also give us information on whether the program has finished executing or not.
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
Related Article — Python Subprocess
Модуль subprocess
Модуль subprocess отвечает за выполнение следующих действий: порождение новых процессов, соединение c потоками стандартного ввода, стандартного вывода, стандартного вывода сообщений об ошибках и получение кодов возврата от этих процессов.
Рекомендуемым подходом к работе с подпроцессами является использование следующих вспомогательных функций для всех случаев, где они могут справиться. Для более сложных случаев может быть использован непосредственно интерфейс Popen.
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None) — выполняет команду, описанную args. Ожидает завершения команды, а затем возвращает код возврата.
Аргументы, приведенные выше, являются лишь наиболее распространенными из них. Полная сигнатура функция в значительной степени такая же, как конструктор Popen. Аргумент timeout передается Popen.wait(). Если тайм-аут истекает, дочерний процесс будет убит, а затем будет поднято исключение TimeoutExpired.
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None) - выполняет команду, описанную args. Ожидает завершения команды, а затем завершается, если код возврата 0, или поднимает исключение CalledProcessError, объект которого возвращает код завершения атрибутом returncode.
subprocess.check_output(args, *, input=None, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None) — выполняет команду и возвращает её вывод. Поднимает исключение CalledProcessError, если код возврата ненулевой.
Создание новых процессов и управление ими в данном модуле обрабатывается классом Popen. Он предлагает большую гибкость, так что разработчики могут справиться с менее распространенными случаями, не охваченными удобными функциями.
subprocess.DEVNULL — значение, которое может использоваться в качестве аргумента stdin, stdout или stderr. Означает, что будет использован специальный файл devnull.
subprocess.PIPE — значение, которое может использоваться в качестве аргумента stdin, stdout или stderr. Означает, что для дочернего процесса будет создан пайп.
subprocess.STDOUT — значение, которое может использоваться в качестве аргумента stderr. Означает, что поток ошибок будет перенаправлен в поток вывода.
Класс subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=()) — Выполняет программу в новом процессе. args – строка или последовательность аргументов программы. Обычно первым указывают исполняемую программу, а затем аргументы, но также ее можно указать в параметре executable.
Popen.poll() — если процесс завершил работу — вернёт код возврата, в ином случае None.
Popen.wait(timeout=None) — ожидает завершения работы процесса и возвращает код возврата. Если в течение timeout процесс не завершился, поднимется исключение TimeoutExpired (которое можно перехватить, после чего сделать ещё раз wait).
Этот метод может вызвать блокировку (зависание), если установлено stdout=PIPE или stderr=PIPE, и дочерний процесс генерирует большое количество данных в stdout и stderr. Использование communicate() позволит избежать этого.
Popen.communicate(input=None, timeout=None) — взаимодействовует с процессом: посылает данные, содержащиеся в input в stdin процесса, ожидает завершения работы процесса, возвращает кортеж данных потока вывода и ошибок. При этом в Popen необходимо задать значение PIPE для stdin (если вы хотите посылать в stdin), stdout, stderr (если вы хотите прочитать вывод дочернего процесса).
Если в течение timeout процесс не завершился, поднимется исключение TimeoutExpired (которое можно перехватить, после чего сделать ещё раз communicate, либо убить дочерний процесс).
Прочитанные данные буферизируются в память, поэтому не стоит применять этот метод в случае огромных выходных данных.
Popen.send_signal(signal) — посылает сигнал signal.
Popen.terminate() — останавливает дочерний процесс.
Popen.kill() — убивает дочерний процесс.
Для вставки кода на Python в комментарий заключайте его в теги