Le terminal reste ouvert du matin au soir, et il sert à lancer trois commandes toujours identiques. La recherche dans les fichiers se fait dans l'éditeur, le renommage en masse à la main, la lecture des logs par copier-coller dans un onglet de navigateur.
La curiosité n'a rien à voir là-dedans. Ce qui manque, c'est le déclencheur. Personne n'apprend xargs par plaisir. On l'apprend le jour où il faut supprimer 4 000 fichiers temporaires répartis dans trente dossiers, et où l'interface graphique se fige au bout de deux minutes.
Les quinze entrées qui suivent couvrent les situations qui reviennent le plus souvent en développement. Elles regroupent une vingtaine d'outils, parce que certains ne servent qu'en couple.
Les exemples sont écrits pour Bash 5 et les outils GNU (coreutils, findutils, grep) tels qu'ils arrivent sur une distribution Linux récente, ce qui correspond aussi à WSL sous Windows. Sur macOS, plusieurs de ces outils viennent de BSD et se comportent différemment : les écarts sont signalés commande par commande. Aucune installation n'est nécessaire, à une exception indiquée en fin de liste.
Le problème : chaque outil graphique réapprend ce que le shell sait déjà faire
Rechercher dans un projet, filtrer, trier, compter, remplacer. Ton éditeur sait faire tout ça, avec une interface, dans son propre périmètre. Le jour où il faut appliquer la même opération sur un serveur distant, sur un fichier de 2 Go, ou dans un script qui tournera toutes les nuits, l'interface disparaît et il ne reste que la ligne de commande.
En formation, l'exercice qui marque le plus les groupes tient en une question posée devant un fichier de log de plusieurs centaines de milliers de lignes : quelle erreur revient le plus souvent. La réponse par l'éditeur de texte prend un quart d'heure et donne un ordre de grandeur approximatif. La réponse par le shell tient en une ligne et donne un décompte exact. Cet écart déclenche plus de vocations que n'importe quel chapitre théorique sur le système de fichiers.
Le déficit se paie surtout au moment du diagnostic. Une application ne répond plus en production, la question « quel processus occupe le port 8080 » demande une réponse en dix secondes, pas en dix minutes de recherche web. C'est le même réflexe que celui décrit dans apprendre à débugger : une procédure connue à la place de la panique.
Le principe : des petits outils qu'on branche les uns aux autres
Chaque commande Unix fait une chose, lit du texte en entrée et écrit du texte en sortie. Le tube, la barre verticale |, envoie la sortie de la première dans l'entrée de la suivante. Toute la puissance du shell tient dans cette règle, implémentée par Ken Thompson à partir d'une idée de Doug McIlroy et datée du 15 janvier 1973 dans les archives de Bell Labs, apparue dans le manuel de la version 3 d'Unix le mois suivant. Rien ne l'a remplacée depuis.
La ligne correspondante traite deux millions d'enregistrements en quelques secondes :
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head
Cette logique de briques assemblées est celle qu'on retrouve ensuite dans un Dockerfile ou dans un job de CI, ce que détaille la roadmap DevOps.
Les quinze entrées, par situation
1. grep : retrouver du texte dans un projet
grep -rn "API_KEY" . --exclude-dir=node_modules
grep -ril "todo" src/
L'option -r descend dans les dossiers, -n affiche le numéro de ligne, -i ignore la casse et -l ne liste que les noms de fichiers. La première commande sert aussi d'audit rapide avant un commit, pour vérifier qu'aucune clé n'a atterri dans le code.
2. find : retrouver des fichiers par nom, taille ou date
find . -name "*.log" -size +100M
find . -type f -mtime -1
La seconde ligne liste tout ce qui a été modifié dans les dernières 24 heures, ce qui aide à comprendre ce qu'un script a touché pendant la nuit. Le find de macOS exige un chemin de départ explicite, d'où le point de find . qui n'est pas facultatif là-bas.
3. xargs : appliquer une commande à une liste
find . -name "*.tmp" -print0 | xargs -0 -r rm
git diff --name-only | xargs -r npx prettier --write
Le couple -print0 et -0 gère les noms de fichiers contenant des espaces, situation qui casse silencieusement la moitié des scripts trouvés en ligne. L'option -r, propre à la version GNU, évite de lancer la commande quand la liste est vide.
4. sed : remplacer dans un ou mille fichiers
sed -i 's/http:/https:/g' config.yml
grep -rlZ "ancienNom" src/ | xargs -0 -r sed -i 's/ancienNom/nouveauNom/g'
Le -Z de grep sépare les noms par un octet nul, comme le fait -print0 côté find. Sans lui, un fichier nommé « mon fichier.txt » devient deux arguments et sed échoue sur les deux. Sur macOS, la version BSD réclame un argument après -i : écris sed -i '' 's/.../.../'. Lance toujours la commande sans -i d'abord pour voir le résultat à l'écran.
5. awk : travailler par colonnes
awk -F',' '$3 > 100 {print $1, $3}' ventes.csv
awk '{somme += $2} END {print somme}' data.txt
Un fichier CSV de 500 Mo s'analyse ainsi sans ouvrir de tableur ni écrire de script Python, tant que les valeurs ne contiennent pas de virgule échappée entre guillemets, cas où awk se trompe de colonne et où un vrai parseur devient nécessaire. La variable $1 désigne la première colonne, -F définit le séparateur. Mon avis, après plusieurs sessions passées à voir des groupes se noyer dedans : apprendre awk comme un langage de programmation ne sert à rien pour un développeur web. Ces deux formes couvrent la quasi-totalité des besoins qui se présentent.
6. sort et uniq : trier et compter
grep "ERROR" app.log | sort | uniq -c | sort -rn | head -20
Cette ligne donne les vingt erreurs les plus fréquentes d'un fichier de log. Elle répond en trente secondes à une question qu'on repousse souvent pendant des semaines. À retenir : uniq ne regroupe que des lignes adjacentes, d'où le premier sort. Si les messages contiennent un horodatage, ils sont tous différents et le comptage ne donne rien : il faut d'abord isoler la partie stable du message avec cut ou awk.
7. cut : extraire un champ
cut -d':' -f1 /etc/passwd
cut -d',' -f2,5 export.csv
Plus limité qu'awk, plus rapide à taper quand le besoin se résume à récupérer une ou deux colonnes. Attention avec un séparateur espace : cut traite chaque espace comme un séparateur, donc deux espaces consécutifs créent un champ vide, là où awk les regroupe.
8. tail : suivre un fichier qui grossit
tail -f var/log/dev.log
tail -f app.log | grep --line-buffered "ERROR"
La seconde ligne affiche en direct uniquement les erreurs qui arrivent. L'option --line-buffered évite que grep retienne les résultats dans son tampon, sinon rien ne s'affiche pendant plusieurs minutes. Si le fichier est recréé par une rotation de logs, tail -F avec un F majuscule reprend le suivi sur le nouveau fichier.
9. less : lire un gros fichier sans le charger
less enorme.log
less +F enorme.log
Ouvrir un fichier de 3 Go dans un éditeur graphique fige la machine, less l'affiche instantanément parce qu'il ne lit que ce qu'il montre. La touche / lance une recherche, n passe à l'occurrence suivante, G saute à la fin et q quitte. La seconde forme, +F, démarre en mode suivi comme tail -f, et Ctrl+C rend la main pour naviguer dans ce qui est déjà écrit.
10. lsof et ss : savoir qui occupe un port
lsof -i :3000
ss -tulpn | grep 8080
Le message « address already in use » se résout en une commande au lieu d'un redémarrage de machine. Sur les distributions Linux récentes, ss, livré avec iproute2, remplace l'ancien netstat du paquet net-tools, qui n'est plus installé par défaut. Sur macOS, ss n'existe pas, lsof fait le travail. Afficher le nom du processus propriétaire demande parfois les droits administrateur.
11. kill et pkill : arrêter un processus
kill 4821
pkill -f "node server.js"
Commence toujours par un kill sans option : il envoie le signal TERM, qui demande au programme de se terminer et lui laisse le temps de fermer ses fichiers et ses connexions. Le -9 envoie KILL, que le processus ne peut pas intercepter, et peut laisser des données à moitié écrites. Avec pkill -f, vérifie d'abord la cible avec pgrep -af et le même motif, sinon tu tues plus large que prévu.
12. du et df : trouver ce qui remplit le disque
df -h
du -sh * | sort -rh | head
La seconde ligne classe le contenu du dossier courant du plus lourd au plus léger. Sur un serveur dont la partition est pleine, elle donne le coupable en une seule commande, souvent un dossier de logs jamais purgé ou un cache Docker. Le motif * ignore les fichiers cachés, donc pense à relancer avec du -sh .[!.]* * si le total ne colle pas.
13. tar : archiver et restaurer
tar -czf sauvegarde.tar.gz dossier/
tar -tzf sauvegarde.tar.gz | head
tar -xzf sauvegarde.tar.gz
Mnémotechnique qui a sauvé des générations : c pour créer, x pour extraire, t pour lister, z pour compresser, f pour nommer le fichier. La ligne du milieu vaut le détour avant toute extraction, parce qu'une archive mal faite déverse cinquante fichiers directement dans le dossier courant.
14. rsync et scp : copier vers un serveur
scp dump.sql utilisateur@serveur:/tmp/
rsync -avzn --delete build/ utilisateur@serveur:/var/www/site/
rsync ne transfère que les différences, ce qui rend une synchronisation répétée quasiment instantanée. Le n ajouté dans l'exemple active la simulation : la commande affiche ce qu'elle ferait sans rien modifier. Retire-le une fois la liste vérifiée. Attention à --delete, qui supprime côté serveur ce qui n'existe plus côté local, et à la barre oblique finale : avec build/ tu copies le contenu, avec build tu copies le dossier lui-même.
15. curl : tester une API sans quitter le terminal
curl -i https://api.exemple.fr/produits/12
curl -X POST https://api.exemple.fr/produits \
-H "Content-Type: application/json" \
-d '{"nom":"Clavier","prix":79}'
L'option -i affiche les en-têtes de réponse, indispensables pour comprendre un problème de cache ou de CORS, sujet détaillé dans comprendre HTTP en profondeur. Une commande curl se colle dans un ticket, se rejoue à l'identique et se glisse dans un script de test, ce qu'aucune capture d'écran d'outil graphique ne permet.
Quatre enchaînements qui servent chaque semaine
Les commandes prennent leur valeur quand on les branche entre elles. Voici quatre combinaisons qui reviennent dans une journée de développement ordinaire.
Repérer les fichiers les plus gros d'un projet, sans compter les dépendances installées :
find src -name "*.php" -print0 | xargs -0 wc -l | sort -n | tail -20
La dernière ligne affichée est un total calculé par wc, pas un fichier. Sur un projet à plusieurs milliers de fichiers, xargs découpe l'appel en plusieurs lots et plusieurs totaux apparaissent : c'est normal, ils s'ignorent.
Repérer les fichiers les plus modifiés du dépôt, souvent ceux qui concentrent la dette :
git log --name-only --pretty=format: | grep -v '^$' | sort | uniq -c | sort -rn | head
Le grep -v '^$' est indispensable : git insère une ligne vide entre chaque commit, et sans ce filtre le premier résultat du classement est le décompte de ces lignes vides.
Sortir la répartition des codes de réponse HTTP d'un serveur web, pour vérifier après une mise en production que le taux d'erreurs n'a pas bougé :
awk '{print $9}' access.log | sort | uniq -c | sort -rn
La position 9 correspond au code de statut dans le format combined d'Apache et de Nginx, celui livré par défaut. Si le format a été personnalisé, compte les champs sur une ligne du fichier avant de reprendre le numéro.
Mesurer le temps de réponse d'une API avant et après une optimisation, sans installer d'outil de mesure :
curl -o /dev/null -s -w "%{time_total}\n" https://api.exemple.fr/produits
Une seule mesure ne dit pas grand-chose, la première requête paie souvent l'ouverture de connexion et la mise en cache. Lance la ligne cinq fois de suite et compare les valeurs stabilisées.
Aucune de ces lignes ne demande de connaître un langage de script. Elles réutilisent les mêmes briques dans un ordre différent, ce qui explique pourquoi apprendre quinze commandes rapporte davantage que d'en apprendre cinquante : la valeur vient des combinaisons, pas du catalogue.
Les pièges
- rm -rf avec une variable. Un
rm -rf "$DOSSIER/"dont la variable est vide vise la racine. Vérifie toujours le contenu avecechoavant d'exécuter la suppression, et ajouteset -uen tête de tes scripts pour qu'une variable non définie arrête l'exécution. - Coller une commande trouvée en ligne sans la lire. Une ligne qui commence par
curl ... | sudo bashexécute du code distant avec les droits administrateur, sans que personne n'ait vu ce code. Cette pratique est à l'origine de compromissions décrites dans application non sécurisée : les risques réels. - chmod 777 en réflexe. Donner tous les droits à tout le monde règle le symptôme et ouvre une porte. Le bon geste consiste à corriger le propriétaire du fichier avec
chown, dans la logique du principe de moindre privilège. - Oublier les guillemets. Un nom de fichier avec un espace se transforme en deux arguments. La règle simple : entoure systématiquement tes variables de guillemets doubles.
- Lancer une commande destructrice sans mode simulation. rsync a
-n, find a-printavant-delete, sed s'exécute sans-i. Ces trois réflexes coûtent dix secondes et évitent des restaurations de sauvegarde. - Supposer que macOS et Linux se comportent pareil. sed, find, date et readlink diffèrent entre les versions BSD et GNU. Un script écrit sur un Mac peut échouer sur le serveur de production, ce que l'article « ça marche sur ma machine » détaille sous l'angle de la portabilité.
Ces quinze entrées forment aussi la base de tout le reste de la chaîne de déploiement. Un fichier Dockerfile, un job de CI, un script de sauvegarde ne contiennent rien d'autre que du shell. C'est ce qui fait le lien entre la formation Linux et ligne de commande pour développeurs et les sujets qui suivent, Docker puis CI/CD avec GitHub Actions. Le shell est la matière première du DevOps, et il continue de servir longtemps après la première mise en production réussie.
Trois suffisent pour commencer, choisies parmi les situations décrites plus haut. Pas quinze.
Questions fréquentes
Ces commandes fonctionnent-elles sous Windows ?
Bash ou Zsh, quelle différence ?
Faut-il apprendre le shell quand une IA écrit les commandes ?
rm -rf mal placé, un chemin absolu douteux ou un --delete qui ne devrait pas être là, devient plus utile que de mémoriser les options. La lecture compte davantage que l'écriture, principe développé dans l'article sur le vibe coding sans perdre le contrôle.Comment retenir les options de chaque commande ?
man commande, l'option --help, et surtout Ctrl+R pour retrouver une commande déjà tapée. Créer des alias dans ton fichier de configuration de shell pour les trois ou quatre lignes que tu réécris chaque semaine élimine le problème pour de bon.