Pular para o conteúdo

Como usar a função subprocess.run

[

O módulo subprocess: Executando programas com Python

por Ian Currie intermediário

Se você já quis simplificar seus scripts de linha de comando ou usar o Python ao lado de aplicativos de linha de comando - ou qualquer outro aplicativo, para falar a verdade - o módulo subprocess do Python pode ajudar. Desde a execução de comandos de shell e aplicativos de linha de comando até o lançamento de aplicativos com interface gráfica, o módulo subprocess do Python pode ser muito útil.

Ao final deste tutorial, você será capaz de:

  • Entender como o módulo subprocess do Python interage com o sistema operacional
  • Executar comandos de shell como ls ou dir
  • Enviar entrada para um processo e utilizar sua saída
  • Lidar com erros ao utilizar o subprocess
  • Entender os casos de uso para o subprocess através de exemplos práticos

Neste tutorial, você terá uma visão geral de alto nível para entender processos, subprocessos e o Python, antes de começar a explorar o módulo subprocess e experimentar um exemplo. Depois disso, você começará a explorar o shell e aprenderá como aproveitar o subprocess do Python com shells e sistemas baseados em Windows e sistemas UNIX. Especificamente, você abordará a comunicação com processos, pipes e manipulação de erros.

Nota: O subprocess não é um módulo de automação de GUI ou uma forma de obter concorrência. Para automação de GUI, você pode querer verificar o PyAutoGUI. Para concorrência, dê uma olhada na seção deste tutorial sobre módulos relacionados ao subprocess.

Depois de ter os conceitos básicos, você explorará algumas ideias práticas de como aproveitar o Python com o subprocess, incluindo o máximo possível de amostras detalhadas, passo a passo e executáveis.

Processos e Subprocessos

Processos e o Sistema Operacional

O sistema operacional gerencia todos os processos que estão em execução em um computador. Ele aloca recursos para cada processo e garante a execução adequada de cada programa. O módulo subprocess permite que você interfira nesse gerenciamento de processos.

Tempo de Vida do Processo

Um processo tem um tempo de vida, começando quando é iniciado e terminando quando é encerrado. O módulo subprocess permite que você controle o tempo de vida de um processo, iniciando-o e encerrando-o conforme necessário.

Processos Ativos no Seu Sistema

Para saber quais processos estão em execução no seu sistema, você pode usar o módulo subprocess para listar todos os processos ativos.

Visão Geral do Módulo subprocess do Python

O módulo subprocess do Python fornece uma interface para a criação e gerenciamento de processos secundários. Ele permite que você crie subprocessos, execute comandos de shell e se comunique com eles através de pipes.

Uso Básico do Módulo subprocess do Python

Para começar a usar o módulo subprocess, você precisa entender os conceitos básicos e fazer um uso simples dele. Você aprenderá a executar um comando de shell, iniciar um aplicativo específico e utilizar o objeto CompletedProcess.

Exemplo de Temporizador

Um exemplo simples de uso do subprocess é criar um temporizador. Você pode usar o módulo subprocess para iniciar o comando sleep do shell e fazer com que o programa Python aguarde um determinado período de tempo.

import subprocess
# Iniciar um temporizador de 5 segundos
subprocess.run(["sleep", "5"])
print("Temporizador encerrado!")

Utilizando o subprocess para Executar Qualquer Aplicativo

Além de executar comandos de shell simples, você também pode usar o módulo subprocess para iniciar qualquer aplicativo disponível no seu sistema operacional. Basta fornecer o caminho para o programa e seus argumentos, se houver.

import subprocess
# Executar o aplicativo "notepad.exe" do Windows
subprocess.run(["notepad.exe"])

O Objeto CompletedProcess

Quando você usa o subprocess para executar comandos, ele retorna um objeto do tipo CompletedProcess que contém informações sobre a execução do comando, como o código de saída e o tempo de execução. Você pode acessar essas informações para tomar decisões ou realizar ações adicionais com base no resultado da execução do comando.

import subprocess
# Executar o comando "ls" e obter o resultado
resultado = subprocess.run(["ls"], capture_output=True, text=True)
# Imprimir a saída do comando
print(resultado.stdout)
# Imprimir o código de saída do comando
print(resultado.returncode)

Exceções do subprocess

As exceções são usadas para lidar com erros que podem ocorrer durante a execução de um comando com o subprocess. Existem várias exceções que podem ser lançadas, dependendo da situação. Você aprenderá sobre as exceções mais comuns relacionadas ao subprocess.

CalledProcessError para Códigos de Saída Diferentes de Zero

A exceção CalledProcessError é lançada quando um comando executado pelo subprocess retorna um código de saída diferente de zero, indicando um erro. Você pode lidar com essa exceção para tomar medidas apropriadas com base no erro recebido.

import subprocess
try:
# Executar o comando "cat arquivo.txt" que não existe
subprocess.run(["cat", "arquivo.txt"], check=True)
except subprocess.CalledProcessError as e:
print("Erro:", e)

TimeoutExpired para Processos que Demoram Demais

A exceção TimeoutExpired é lançada quando um processo executado pelo subprocess demora mais tempo que o especificado. Você pode usar essa exceção para definir um tempo limite para a execução do processo e lidar com a situação caso o tempo limite seja atingido.

import subprocess
try:
# Executar o comando "sleep 10" com um tempo limite de 5 segundos
subprocess.run(["sleep", "10"], timeout=5)
except subprocess.TimeoutExpired as e:
print("Tempo limite excedido!")

FileNotFoundError para Programas que Não Existem

A exceção FileNotFoundError é lançada quando você tenta executar um programa que não existe no sistema. Você pode lidar com essa exceção para informar ao usuário que o programa não está disponível.

import subprocess
try:
# Executar o programa "meu_programa" que não existe
subprocess.run(["meu_programa"])
except FileNotFoundError:
print("O programa não está disponível.")

Um Exemplo de Tratamento de Exceção

Aqui está um exemplo que combina todas as exceções que aprendemos até agora em um programa Python que lida com diferentes erros ao executar comandos com o subprocess.

import subprocess
try:
# Executar o comando "cat arquivo.txt" que não existe
subprocess.run(["cat", "arquivo.txt"], check=True, timeout=5)
except subprocess.CalledProcessError as e:
print("Erro:", e)
except subprocess.TimeoutExpired:
print("Tempo limite excedido.")
except FileNotFoundError:
print("O programa não está disponível.")

Introdução ao Shell e Programas Baseados em Texto com subprocess

Uma das principais vantagens do uso do subprocess é a capacidade de interagir com programas baseados em texto, como shells de sistema operacional e aplicativos de linha de comando. Você aprenderá sobre os casos de uso do shell e do subprocess, e como utilizar o subprocess com shells baseados em UNIX e Windows.

Casos de Uso para o Shell e subprocess

Existem várias situações em que você pode querer usar o shell e o subprocess, como automatizar tarefas de linha de comando, extrair informações do sistema operacional ou executar arquivos de script.

Uso Básico do subprocess com Shells Baseados em UNIX

Para executar comandos em um shell baseado em UNIX, você pode usar o módulo subprocess para iniciar um novo processo e executar o comando desejado.

import subprocess
# Executar o comando "ls" no shell baseado em UNIX
subprocess.run(["ls"])

Uso Básico do subprocess com Shells do Windows

Para executar comandos em um shell do Windows, como o Prompt de Comando (cmd.exe), você pode usar o módulo subprocess para iniciar um novo processo e executar o comando desejado.

import subprocess
# Executar o comando "dir" no shell do Windows
subprocess.run(["dir"], shell=True)

Um Aviso de Segurança

Ao usar o subprocess com shells do Windows, é importante estar ciente de possíveis vulnerabilidades de segurança. Certifique-se de que os comandos passados para o shell sejam seguros e não permitam a execução de comandos maliciosos.

Comunicação com Processos

Os Fluxos de E/S Padrão

Quando você executa um processo com o subprocess, ele possui três fluxos de entrada e saída padrão: stdin (entrada padrão), stdout (saída padrão) e stderr (saída de erro padrão). Você pode redirecionar esses fluxos para se comunicar com o processo.

Exemplo de Gerador de Números Mágicos

Aqui está um exemplo de como você pode usar o subprocess para se comunicar com um programa que gera números mágicos. O programa gera um número aleatório e você pode adivinhar qual é. Ao enviar sua tentativa para a entrada padrão do programa, você receberá uma resposta na saída padrão.

import subprocess
# Iniciar o programa gerador de números mágicos
processo = subprocess.Popen(["python", "gerador_numeros_magicos.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
# Enviar uma tentativa para a entrada padrão do programa
tentativa = "5\n"
processo.stdin.write(tentativa)
# Ler a resposta do programa a partir da saída padrão
resposta = processo.stdout.readline()
# Imprimir a resposta do programa
print(resposta)

A Decodificação dos Fluxos Padrão

O subprocess retorna os fluxos de entrada e saída padrão como objetos do tipo bytes. Para trabalhar com esses objetos de forma mais conveniente, você precisará decodificá-los em texto.

import subprocess
# Executar um comando e obter a saída decodificada
resultado = subprocess.run(["ls"], capture_output=True, text=True)
# Imprimir a saída decodificada do comando
print(resultado.stdout)

Exemplo de Jogo de Reação

Aqui está um exemplo de como você pode usar o subprocess para criar um jogo de reação. O programa exibe uma mensagem e você deve pressionar qualquer tecla no teclado o mais rápido possível. O subprocess é usado para esperar pela entrada do usuário e medir o tempo de resposta.

import subprocess
import time
# Iniciar o programa do jogo de reação
processo = subprocess.Popen(["python", "jogo_reacao.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
# Esperar até ver a mensagem na saída padrão do programa
while "Pressione uma tecla:" not in resposta:
resposta = processo.stdout.readline()
# Registrar o tempo inicial
tempo_inicial = time.time()
# Enviar uma tecla para a entrada padrão do programa
processo.stdin.write("\n")
# Ler a resposta do programa até ver a mensagem final
while "Tempo de reação:" not in resposta:
resposta = processo.stdout.readline()
# Calcular o tempo de reação
tempo_final = time.time()
tempo_reacao = tempo_final - tempo_inicial
# Imprimir o tempo de reação
print("Tempo de reação:", tempo_reacao, "segundos")

Pipes e o Shell

Introdução a Pipes

Pipes são uma forma de comunicação entre processos no shell. Eles permitem que a saída de um processo seja a entrada de outro processo, criando uma cadeia de processos conectados.

Os Pipes do subprocess

O módulo subprocess do Python suporta pipes para comunicação entre os processos que você executa. Você pode redirecionar a saída de um processo para a entrada de outro processo, criando uma estrutura de pipes.

Simulação de Pipes com a Função run()

Aqui está um exemplo de como você pode simular o uso de pipes com a função run() do subprocess. O primeiro processo gera números aleatórios e os redireciona para o segundo processo, que os exibe na saída padrão.

import subprocess
# Processo 1: Gerar números aleatórios
processo1 = subprocess.Popen(["python", "gerador_numeros.py"], stdout=subprocess.PIPE)
# Processo 2: Exibir números na saída padrão
processo2 = subprocess.Popen(["python", "exibir_numeros.py"], stdin=processo1.stdout)
# Esperar pelos processos terminarem
processo1.wait()
processo2.wait()

Ideias Práticas

Criando um Novo Projeto: Um Exemplo

Uma ideia prática para usar o subprocess é automatizar o processo de criação de um novo projeto. Você pode criar um script Python que use o subprocess para executar os comandos necessários para criar a estrutura de diretórios e arquivos do projeto.

import subprocess
# Criar a estrutura de diretórios do projeto
subprocess.run(["mkdir", "meu_projeto"])
subprocess.run(["mkdir", "meu_projeto/src"])
subprocess.run(["mkdir", "meu_projeto/testes"])
# Criar arquivos de exemplo no projeto
subprocess.run(["touch", "meu_projeto/src/main.py"])
subprocess.run(["touch", "meu_projeto/testes/teste_main.py"])

Alterando Atributos Extendidos

Outra ideia prática é a manipulação de atributos extendidos em arquivos. Você pode usar o subprocess para executar comandos como setfattr ou getfattr para alterar ou obter atributos extendidos de arquivos.

import subprocess
# Definir um atributo extendido em um arquivo
subprocess.run(["setfattr", "-n", "user.comment", "-v", "Comentário do arquivo", "arquivo.txt"])
# Obter um atributo extendido de um arquivo
subprocess.run(["getfattr", "-n", "user.comment", "arquivo.txt"])

Módulos Python Associados ao subprocess

Existem vários módulos relacionados ao subprocess que podem ser úteis para diferentes tarefas. Alguns desses módulos incluem:

  • os - Para interagir com o sistema operacional e manipular caminhos de arquivos
  • shutil - Para realizar operações de alto nível em arquivos e diretórios
  • tempfile - Para a criação de arquivos temporários
  • argparse - Para análise de argumentos de linha de comando
  • multiprocessing - Para trabalhar com processos paralelos

Consulte a documentação oficial do Python para obter mais informações sobre esses módulos e como usá-los.

A Classe Popen

A classe Popen é uma forma mais flexível de executar comandos com o subprocess. Ela oferece mais opções de controle e comunicação com os processos que você executa.

Usando o Popen()

Você pode usar a classe Popen para iniciar um processo e controlá-lo de forma mais granular. Isso permite que você redirecione os fluxos de entrada e saída, especifique o diretório de trabalho e configure outras opções específicas do processo.

import subprocess
# Iniciar um novo processo usando a classe Popen
processo = subprocess.Popen(["ls"], stdout=subprocess.PIPE)
# Ler a saída do processo a partir da saída padrão
saida = processo.stdout.read()
# Imprimir a saída do processo
print(saida)

Conectando Dois Processos com Pipes

Uma das principais vantagens da classe Popen é a capacidade de conectar dois processos com pipes. Isso permite que você crie uma estrutura de processos interconectados, onde a saída de um processo é a entrada de outro.

import subprocess
# Processo 1: Gerar números aleatórios
processo1 = subprocess.Popen(["python", "gerador_numeros.py"], stdout=subprocess.PIPE)
# Processo 2: Exibir números na saída padrão
processo2 = subprocess.Popen(["python", "exibir_numeros.py"], stdin=processo1.stdout)
# Esperar pelos processos terminarem
processo1.wait()
processo2.wait()

Interagindo Dinamicamente com um Processo

Outra vantagem da classe Popen é a capacidade de interagir dinamicamente com um processo em execução. Isso permite que você envie entrada para o processo e leia a saída conforme ela é gerada.

import subprocess
# Iniciar o programa do jogo de reação
processo = subprocess.Popen(["python", "jogo_reacao.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
# Enviar uma tecla para a entrada padrão do programa
processo.stdin.write("\n")
# Ler a resposta do programa a partir da saída padrão
resposta = processo.stdout.readline()
# Imprimir a resposta do programa
print(resposta)

Conclusão

Neste tutorial, você aprendeu sobre o módulo subprocess do Python e como ele pode ser usado para executar programas e interagir com processos. Você viu como executar comandos de shell, lidar com erros e se comunicar com processos usando pipes. Você também explorou algumas ideias práticas de como utilizar o subprocess em diferentes cenários.

O uso do subprocess pode ser muito útil ao trabalhar com programação de linha de comando e automação de processos. Agora que você tem o conhecimento básico do módulo subprocess, você pode explorar ainda mais seus recursos e encontrar novas maneiras de aproveitar o poder do Python em suas tarefas diárias.