Un shell est un programme qui permet aux utilisateurs d’interagir avec le système d’exploitation en exécutant des commandes. Développer un shell Linux en Python est un excellent exercice pour comprendre le fonctionnement des interfaces en ligne de commande (CLI), la gestion des processus et les interactions avec le système.
Dans cet article, nous allons construire un shell simple en Python qui prend en charge :
✅ L’exécution de commandes système (comme ls, pwd, cat, etc.)
✅ Les commandes intégrées (cd, exit)
✅ La gestion des processus avec subprocess
✅ Les redirections et les pipes (|, >, <)
1. Comprendre les bases d’un shell
Un shell fonctionne selon un cycle REPL (Read-Eval-Print Loop) :
1️⃣ Lire : Accepter une entrée utilisateur.
2️⃣ Analyser : Découper la commande en tokens (mots-clés, arguments).
3️⃣ Exécuter : Lancer la commande en tant que processus.
4️⃣ Afficher : Montrer le résultat à l’utilisateur.
Voici un exemple simple d’un shell fonctionnant en boucle :
pythonCopierModifierwhile True:
command = input("$ ") # Lire la commande
if command == "exit":
break
print(f"Vous avez tapé : {command}")
2. Exécution de commandes système avec subprocess
Le module subprocess permet de lancer des programmes externes comme ls, pwd, echo, etc.
Exemple :
pythonCopierModifierimport subprocess
while True:
command = input("$ ").strip()
if command.lower() == "exit":
break
try:
subprocess.run(command.split()) # Exécuter la commande
except FileNotFoundError:
print("Commande inconnue")
Explication :
command.split()découpe l’entrée utilisateur en une liste (ls -ldevient['ls', '-l']).subprocess.run()exécute la commande.try/exceptgère les erreurs si la commande n’existe pas.
3. Implémentation des commandes intégrées (cd, exit)
Certaines commandes comme cd ou exit sont des commandes intégrées car elles modifient l’environnement du shell. Elles ne peuvent pas être exécutées avec subprocess.
Nous utilisons os pour les gérer :
pythonCopierModifierimport os
import subprocess
def change_directory(path):
try:
os.chdir(path)
except FileNotFoundError:
print(f"Dossier introuvable : {path}")
while True:
command = input("$ ").strip()
if command.lower() == "exit":
break
elif command.startswith("cd "):
path = command.split(maxsplit=1)[1] # Extraire le chemin
change_directory(path)
else:
try:
subprocess.run(command.split())
except FileNotFoundError:
print("Commande inconnue")
4. Gestion des redirections (>, <, >>)
Un shell permet de rediriger la sortie (> pour écraser un fichier, >> pour ajouter) et l’entrée (< pour lire un fichier).
Exemple :
shCopierModifierecho "Hello" > test.txt # Écrit "Hello" dans test.txt
cat < test.txt # Affiche le contenu de test.txt
echo "New Line" >> test.txt # Ajoute "New Line"
Implémentation en Python
Nous devons :
- Vérifier si
>ou<est présent dans la commande. - Ouvrir le fichier et rediriger
stdoutoustdin.
pythonCopierModifierdef execute_command(command):
if ">" in command: # Redirection de sortie
parts = command.split(">")
cmd, file_name = parts[0].strip(), parts[1].strip()
with open(file_name, "w") as file:
subprocess.run(cmd.split(), stdout=file)
elif ">>" in command: # Append (ajout)
parts = command.split(">>")
cmd, file_name = parts[0].strip(), parts[1].strip()
with open(file_name, "a") as file:
subprocess.run(cmd.split(), stdout=file)
elif "<" in command: # Redirection d’entrée
parts = command.split("<")
cmd, file_name = parts[0].strip(), parts[1].strip()
with open(file_name, "r") as file:
subprocess.run(cmd.split(), stdin=file)
else:
subprocess.run(command.split())
while True:
command = input("$ ").strip()
if command.lower() == "exit":
break
elif command.startswith("cd "):
change_directory(command.split(maxsplit=1)[1])
else:
execute_command(command)
5. Gestion des pipes (|)
Les pipes (|) permettent d’enchaîner plusieurs commandes en connectant la sortie de l’une à l’entrée de l’autre.
Exemple :
shCopierModifierls -l | grep py
ici, ls -l affiche une liste de fichiers et grep py filtre ceux contenant « py ».
Implémentation en Python
Nous devons :
- Séparer les commandes avec
|. - Utiliser
subprocess.Popen()pour créer un pipeline entre elles.
pythonCopierModifierdef execute_piped_commands(command):
commands = [cmd.strip().split() for cmd in command.split("|")]
prev_process = None
for cmd in commands:
if prev_process:
process = subprocess.Popen(cmd, stdin=prev_process.stdout, stdout=subprocess.PIPE)
prev_process.stdout.close() # Fermer la sortie précédente
else:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
prev_process = process
if prev_process:
prev_process.communicate() # Exécuter la dernière commande
while True:
command = input("$ ").strip()
if command.lower() == "exit":
break
elif "|" in command:
execute_piped_commands(command)
elif command.startswith("cd "):
change_directory(command.split(maxsplit=1)[1])
else:
execute_command(command)
6. Ajout d’un prompt personnalisé
Pour rendre notre shell plus réaliste, ajoutons un prompt qui affiche le répertoire courant :
pythonCopierModifierimport os
def get_prompt():
return f"{os.getcwd()}$ "
while True:
command = input(get_prompt()).strip()
if command.lower() == "exit":
break
elif "|" in command:
execute_piped_commands(command)
elif command.startswith("cd "):
change_directory(command.split(maxsplit=1)[1])
else:
execute_command(command)
7. Conclusion et améliorations possibles
Nous avons construit un shell Linux simple en Python qui prend en charge :
✅ L’exécution de commandes externes
✅ Les commandes intégrées (cd, exit)
✅ Les redirections (>, <, >>)
✅ Les pipes (|)
✅ Un prompt dynamique
Améliorations possibles 🚀
🔥 Support des alias (alias ll='ls -l')
🔥 Ajout d’un historique de commandes
🔥 Prise en charge des variables d’environnement ($HOME)
🔥 Complétion automatique avec readline
Avec ces fonctionnalités, vous pouvez construire un shell personnalisé pour Linux, macOS ou Windows ! 💻🚀

















