HOWTO · Python

Comment exécuter des scripts Bash dans Python

Apprenez à exécuter des scripts Bash en utilisant Python avec notre guide complet. Explorez des méthodes comme subprocess, os.system et subprocess.Popen pour exécuter des commandes Bash efficacement. Améliorez vos compétences en automatisation et rationalisez les flux de travail en intégrant des scripts Bash dans vos applications Python.

Sur cette page

Pour la plupart des scripts Bash qui doivent se terminer avant que Python poursuive son exécution, utilisez subprocess.run. Cette fonction permet de transmettre les arguments séparément, de capturer stdout et stderr et de vérifier le returncode du processus. Bash doit être installé et accessible depuis Python : cette approche dépend donc de l’environnement hôte et n’est pas portable sur les systèmes dépourvus de Bash. L’exemple ci-dessous crée son propre fichier de script, lui transmet un nom en argument et affiche le résultat capturé.

Méthode 1 : utiliser le module subprocess

Cet exemple autonome crée un petit script Bash, lui transmet un argument et capture les deux flux de sortie. Le script Bash affiche un message de bienvenue ; Python affiche ensuite le texte capturé et le statut du processus. Dans l’exemple inchangé, le message de bienvenue et l’étiquette « Return code » affichés restent en anglais.

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

La liste d’arguments conserve le chemin du script et Ada comme deux arguments distincts. Avec la valeur par défaut shell=False, Python lance directement Bash au lieu de demander à un shell d’analyser la liste. Cela évite l’analyse par un shell de ces arguments, mais ne constitue pas une garantie de sécurité universelle : validez les entrées et tenez compte de ce que fait le script lui-même. Un returncode égal à zéro indique une réussite ; une valeur différente de zéro indique que le processus a signalé un échec. stderr est un flux distinct destiné aux diagnostics, et la présence de texte dans ce flux ne signifie pas, à elle seule, que la commande a échoué. capture_output=True rend stdout et stderr accessibles dans l’objet résultat.

Méthode 2 : utiliser os.system

Utilisez os.system uniquement lorsqu’une commande simple suffit et que Python n’a pas besoin d’en capturer la sortie. Cette fonction accepte une seule chaîne de commande, l’exécute au moyen d’un shell système et envoie les flux de la commande vers les flux standard du processus appelant. Sa valeur de retour dépend du système et peut encoder le statut du processus au lieu d’être égale à son code de sortie ; ne la considérez donc pas comme un code de sortie direct et portable. La fonction ne fournit pas d’objet résultat donnant directement accès à stdout ou à stderr. Évitez de construire sa chaîne de commande à partir de données non fiables, car l’analyse par le shell peut leur donner une signification particulière. Pour transmettre des arguments distincts, capturer les flux et examiner le statut de façon fiable, préférez subprocess.

Méthode 3 : utiliser subprocess.Popen

Choisissez subprocess.Popen lorsque vous avez besoin d’un contrôle plus fin sur un processus en cours d’exécution, par exemple pour gérer sa durée de vie ou connecter des tubes. Pour un échange de données fini, définissez stdin=subprocess.PIPE lors de la création du processus, puis appelez communicate(input=...) pour lui transmettre l’entrée et récupérer les flux capturés une fois le processus terminé. Sans ce tube d’entrée, communicate(input=...) ne peut pas envoyer de données au processus enfant. Cette méthode ne fournit pas la sortie en temps réel. Si vous créez des tubes pour les deux flux de sortie, videz-les avec communicate() ; attendre la fin d’un processus enfant pendant que son tube se remplit peut provoquer un interblocage. Pour lire la sortie en direct, lisez et videz les flux explicitement au lieu de traiter communicate() comme une API de diffusion en continu. Le comportement exact des tubes dépend de la plateforme et du processus.

Conclusion

Pour un script Bash qui s’exécute jusqu’à son terme, subprocess.run est généralement le choix le plus clair : transmettez une liste, capturez les flux si nécessaire et utilisez returncode pour déterminer si l’exécution a réussi. Réservez os.system aux commandes shell simples qui ne nécessitent pas de gestion de la sortie, et utilisez subprocess.Popen lorsqu’un contrôle explicite du processus ou des échanges avec celui-ci sont nécessaires. Vérifiez que Bash est installé et disponible dans l’environnement où s’exécute le programme Python : le script ne peut être lancé que si Python peut trouver l’exécutable Bash.

FAQ

  1. Quelle est la meilleure façon d’exécuter un script Bash depuis Python ?
    Pour la plupart des scripts qui se terminent avant que Python poursuive son exécution, utilisez subprocess.run. Cette fonction prend en charge les listes d’arguments, la capture des flux et l’accès au statut du processus via returncode.

  2. Comment capturer la sortie d’un script ?
    Définissez capture_output=True et text=True dans subprocess.run, puis lisez stdout et stderr dans l’objet renvoyé. Avec Popen, connectez les tubes nécessaires et appelez communicate() pour récupérer les flux une fois le processus terminé ; cette méthode collecte la sortie au lieu de la diffuser en direct. stderr peut contenir des diagnostics même si le processus réussit : vérifiez son statut avec returncode.

  3. Transmettre une liste est-il sûr ?
    Avec shell=False, une liste évite que les arguments transmis soient analysés par un shell. Cela réduit le risque d’injection dans le shell, mais ne rend pas sûrs tous les scripts ni toutes les entrées ; validez les valeurs et tenez compte du comportement implémenté par le script.

  4. Puis-je transmettre des arguments à un script Bash ?
    Oui. Ajoutez chaque argument comme élément distinct après le chemin du script dans la liste d’arguments de subprocess. os.system prend une seule chaîne de commande et ne permet donc pas de transmettre les arguments de la même manière structurée.

  5. Comment fournir une entrée au script ?
    Pour un échange simple et fini, utilisez subprocess.run avec input=.... Si vous avez besoin d’un contrôle plus fin du processus, utilisez Popen avec stdin=subprocess.PIPE et communicate(input=...). communicate() transmet l’entrée et récupère les flux du processus une fois celui-ci terminé.