HOWTO · Python
Como Executar Scripts Bash em Python
Aprenda como executar scripts Bash usando Python com nosso guia abrangente. Explore métodos como subprocess, os.system e subprocess.Popen para executar comandos Bash de forma eficiente. Aprimore suas habilidades de automação e otimize fluxos de trabalho integrando scripts Bash em suas aplicações Python.
Nesta página
Use subprocess.run para a maioria dos scripts Bash que devem terminar antes de o Python continuar. Com ele, é possível passar argumentos separadamente, capturar stdout e stderr e verificar o returncode do processo. O Bash precisa estar instalado e disponível para o Python; por isso, essa abordagem depende do ambiente do sistema e não é portátil para sistemas sem Bash. O exemplo a seguir cria o próprio arquivo de script, passa um nome como argumento e exibe o resultado capturado.
Método 1: usando o módulo subprocess
Este exemplo autocontido cria um pequeno script Bash, passa um argumento para ele e captura os dois fluxos de saída. O script Bash exibe uma saudação; em seguida, o Python mostra o texto capturado e o status do processo. A saudação e o rótulo “Return code” exibidos no exemplo permanecem em inglês, pois os blocos correspondentes não foram alterados.
import subprocess
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as directory:
script_path = Path(directory) / "greet.sh"
script_path.write_text(
'#!/usr/bin/env bash\nprintf "Hello, %s!\\n" "$1"\n',
encoding="utf-8",
)
result = subprocess.run(
["bash", str(script_path), "Ada"],
capture_output=True,
text=True,
check=False,
)
print(result.stdout, end="")
print(f"Return code: {result.returncode}")
Hello, Ada!
Return code: 0
A lista de argumentos mantém o caminho do script e Ada como argumentos separados. Com o padrão shell=False, o Python inicia o Bash diretamente, sem pedir a um shell que interprete a lista. Isso evita a interpretação desses argumentos pelo shell, mas não é uma garantia universal de segurança: valide as entradas e considere o que o próprio script faz. Um returncode igual a zero indica sucesso; um valor diferente de zero indica que o processo informou uma falha. stderr é um fluxo separado para mensagens de diagnóstico, e a presença de texto nele, por si só, não significa que o comando falhou. capture_output=True disponibiliza stdout e stderr no objeto de resultado.
Método 2: usando os.system
Use os.system apenas quando um comando simples for suficiente e o Python não precisar capturar a saída. Ele recebe uma única string de comando, executa-a por meio de um shell do sistema e envia os fluxos do comando para os fluxos padrão do processo ao redor. O valor retornado depende do sistema e pode codificar o status do processo em vez de corresponder ao código de saída do processo filho; portanto, não o trate como um código de saída direto e portátil. Esse método não fornece um objeto de resultado com acesso direto a stdout ou stderr. Evite montar a string de comando com entradas não confiáveis, pois o shell pode interpretá-las de maneira especial. Para argumentos separados, fluxos capturados e uma verificação confiável do status, prefira subprocess.
Método 3: usando subprocess.Popen
Escolha subprocess.Popen quando precisar de controle de nível mais baixo sobre um processo em execução, por exemplo, para gerenciar seu ciclo de vida ou conectar pipes. Para uma troca finita de dados, defina stdin=subprocess.PIPE ao criar o processo e depois chame communicate(input=...) para enviar a entrada e coletar os fluxos capturados quando o processo terminar. Sem esse pipe de entrada, communicate(input=...) não consegue enviar dados ao processo filho. Esse método não entrega a saída em tempo real. Se criar pipes para os dois fluxos de saída, esvazie-os com communicate(); esperar pelo processo filho enquanto um pipe enche pode causar um deadlock. Para transmitir dados em tempo real, leia e esvazie os fluxos deliberadamente, em vez de tratar communicate() como uma API de streaming. O comportamento exato dos pipes depende da plataforma e do processo.
Conclusão
Para um script Bash que deve ser executado até o fim, subprocess.run costuma ser a opção mais clara: passe uma lista, capture os fluxos quando necessário e use returncode para verificar o sucesso. Reserve os.system para comandos simples do shell que não exigem tratamento da saída e use subprocess.Popen quando precisar controlar explicitamente o processo ou se comunicar com ele. Verifique se o Bash está instalado e disponível no ambiente em que o programa Python será executado; o script só pode ser iniciado se o Python conseguir encontrar o executável do Bash.
Perguntas frequentes
-
Qual é a melhor maneira de executar um script Bash pelo Python?
Usesubprocess.runpara a maioria dos scripts que terminam antes de o Python precisar continuar. Ele permite passar uma lista de argumentos, capturar os fluxos e consultar o status do processo por meio dereturncode. -
Como capturo a saída de um script?
Definacapture_output=Trueetext=Trueemsubprocess.rune, em seguida, leiastdoutestderrdo objeto retornado. ComPopen, conecte os pipes necessários e chamecommunicate()para coletar os fluxos depois que o processo terminar; isso coleta a saída, mas não a transmite em tempo real.stderrpode conter mensagens de diagnóstico mesmo quando o processo é bem-sucedido; usereturncodepara verificar o status. -
Passar uma lista é seguro?
Comshell=False, a lista evita que o shell interprete os argumentos fornecidos. Isso reduz o risco de injeção de comandos no shell, mas não torna todo script ou entrada seguro; valide os valores e considere o comportamento implementado pelo script. -
Posso passar argumentos para um script Bash?
Sim. Adicione cada argumento como um item separado depois do caminho do script na lista de argumentos desubprocess.os.systemrecebe uma única string de comando e, portanto, não oferece a mesma forma estruturada de passar argumentos. -
Como posso fornecer entrada ao script?
Usesubprocess.runcominput=...para uma troca simples e finita, ou usePopencomstdin=subprocess.PIPEecommunicate(input=...)quando precisar de controle de nível mais baixo sobre o processo.communicate()envia a entrada e coleta os fluxos do processo depois que o processo filho termina.