Jour 38 Day 38 · mardi 29 septembre 2026 Tuesday 29 September 2026 DevOps Fondamental

Linux pour développeur Linux for developers

Processus et signaux, permissions, pipes, systemd et les commandes qui sauvent : le socle Linux qu'on attend d'un stagiaire dev — et la méthode pour déboguer un serveur qui ne répond plus. Processes and signals, permissions, pipes, systemd and the commands that save the day: the Linux foundation expected from a dev intern — plus the method for debugging a server that stopped responding.

L’essentiel

Vos serveurs tournent sous Linux. Vos conteneurs Docker aussi. Votre CI, votre Raspberry Pi, et 100 % du top 500 des supercalculateurs. Un développeur qui sait se débrouiller dans un shell Linux débogue seul ce que les autres escaladent — c’est exactement ce qu’un recruteur cherche chez un stagiaire.

Deux idées fondatrices structurent tout le système :

  • Tout est fichier — les disques (/dev/sda), les sockets, et même l’état du noyau : /proc est un filesystem virtuel où chaque processus a son répertoire (/proc/1234/), où cat /proc/cpuinfo lit les CPU et /proc/meminfo la mémoire. Lire, écrire, rediriger : une seule interface pour tout.
  • Petits outils composables — la philosophie Unix : chaque programme fait une chose bien, le texte est l’interface universelle, et le pipe | les assemble en chaînes puissantes. grep ne sait pas trier, sort ne sait pas filtrer — ensemble, ils font de l’analyse de logs.

Comment ça marche

Processus : fork, exec, signaux

Un nouveau processus naît toujours par fork() (le parent se clone) généralement suivi d’exec() (le clone se remplace par le nouveau programme) — c’est ainsi que votre shell lance chaque commande. Chaque processus a un PID ; le tout premier, PID 1 (systemd), démarre le système et adopte les orphelins.

On parle aux processus par signaux :

SignalN°EffetInterceptable ?
SIGHUP1terminal fermé / recharger la configoui
SIGINT2Ctrl+Coui
SIGTERM15« termine-toi proprement » (défaut de kill)oui
SIGKILL9mort immédiate, décidée par le noyaunon
SIGSEGV11accès mémoire invalideoui
SIGSTOP / SIGCONT19 / 18pause / reprisenon / oui

SIGTERM vs SIGKILL, la nuance qui compte : SIGTERM est une demande — le processus peut fermer ses connexions, flusher ses buffers, sauvegarder, puis sortir. SIGKILL ne lui parvient jamais : le noyau le supprime, sans aucun cleanup. C’est le protocole exact de docker stop : SIGTERM au PID 1 du conteneur, 10 secondes de grâce, puis SIGKILL. Une app qui n’écoute pas SIGTERM (ou lancée derrière un shell qui ne relaie pas les signaux) meurt brutalement à chaque déploiement.

stdin, stdout, stderr et redirections

Chaque processus démarre avec trois flux numérotés : l’entrée standard (0), la sortie standard (1) et la sortie d’erreur (2). Le shell peut les rebrancher où il veut :

        stdin (0)             stdout (1)
clavier ─────────▶ processus ─────────▶ terminal
                       │
                       └─── stderr (2) ─────▶ terminal

cmd > out.log     stdout → fichier (écrase ; >> ajoute)
cmd 2> err.log    stderr → fichier
cmd > f 2>&1      les deux → f (l'ordre compte !)
cmd1 | cmd2       stdout de cmd1 → stdin de cmd2

Le pipe est la pièce maîtresse : il branche la sortie d’un programme sur l’entrée du suivant, sans fichier intermédiaire. Un cas réel — trouver les IP qui martèlent votre endpoint de login :

grep "POST /api/login" access.log \
  | awk '{print $1}'   # extraire la 1re colonne : l'IP
  | sort               # uniq exige des lignes adjacentes
  | uniq -c            # compter les occurrences par IP
  | sort -rn           # tri numérique décroissant
  | head -10           # top 10 des IP les plus insistantes

💡 Réflexe à montrer — le sort avant uniq -c n’est pas décoratif : uniq ne fusionne que les lignes adjacentes. L’oublier donne des comptes faux — le genre de détail qui prouve en entretien que vous avez vraiment pratiqué.

Concepts clés à maîtriser

  • Permissions rwx — trois triplets : propriétaire, groupe, autres. En octal : r=4, w=2, x=1. chmod 755 = rwxr-xr-x (exécutable par tous, modifiable par le seul propriétaire) ; 600 = rw------- (clé SSH privée). sudo exécute une commande en root — un privilège à justifier, pas un réflexe.
  • Variables d’environnement & PATH — un ensemble clé=valeur hérité par les processus enfants (export API_URL=…). Le PATH liste les répertoires où le shell cherche les commandes, dans l’ordre — c’est pourquoi un script local se lance avec ./script.sh, et pourquoi which python lève les doutes.
  • systemd en survol — le gestionnaire de services : systemctl status nginx (état), start/stop/restart, enable (démarrage au boot). Les logs passent par journalctl -u nginx -f (le -f suit en direct).
  • Les commandes qui sauvent — grep -rn "motif" . (chercher dans le code), find . -name "*.log" (trouver des fichiers), ps aux (processus en cours), ss -tlnp (ports en écoute et par qui), tail -f app.log (suivre un log en direct), df -h (espace disque), du -sh * (qui prend la place), top/htop (CPU/RAM en temps réel).
  • SSH & clés — une paire clé publique/privée remplace le mot de passe : la publique va dans ~/.ssh/authorized_keys du serveur, la privée ne quitte jamais votre machine. Plus sûr (rien à deviner par force brute) et scriptable (CI, déploiements).

🎤 En entretien — « un serveur ne répond plus, tu fais quoi ? » Déroulez une méthode, pas une liste : (1) j’accède — ping, puis SSH ; (2) top — CPU saturé ? plus de RAM ? un processus fou ? ; (3) df -h — disque plein, la cause la plus bête et la plus fréquente ; (4) ss -tlnp — mon service écoute-t-il encore son port ? ; (5) systemctl status app puis journalctl -u app -n 100 ou tail -f sur ses logs — l’erreur y est presque toujours. Une démarche structurée vaut dix commandes récitées.

En entretien

« SIGTERM vs SIGKILL ? » — SIGTERM (15) demande un arrêt propre : le processus peut l’intercepter pour fermer connexions et buffers. SIGKILL (9) est ininterceptable : le noyau tue sans cleanup. Bonus : docker stop envoie SIGTERM, attend 10 s, puis SIGKILL — d’où l’importance de gérer SIGTERM dans une app conteneurisée.

« Que signifie chmod 640 ? » — Octal : 6 = rw- (propriétaire), 4 = r— (groupe), 0 = --- (autres). Lecture-écriture pour le propriétaire, lecture seule pour le groupe, rien pour le reste du monde — typique d’un fichier de config avec secrets.

« Comment un processus est-il créé sous Linux ? » — Par fork() : le parent se clone (même code, mémoire copiée) ; puis en général exec() remplace l’image du clone par le nouveau programme. Le shell fait fork + exec pour chaque commande, et wait() pour récupérer le code de sortie.

« À quoi sert le PATH ? » — C’est la liste ordonnée des répertoires où le shell cherche un exécutable quand on tape une commande sans chemin. Premier trouvé, premier servi — d’où les surprises quand deux versions d’un outil cohabitent (which pour trancher).

« Comment lire les logs d’un service en production ? » — Service systemd : journalctl -u nom-du-service -f (ou -n 200 pour les 200 dernières lignes). Fichier classique : tail -f /var/log/app.log, filtré avec grep. Conteneur : docker logs -f, puisque l’app logge sur stdout/stderr.

Pièges & idées reçues

⚠️ Les deux réflexes toxiques — kill -9 d’entrée de jeu : le processus meurt sans flusher ni libérer ses ressources (fichiers de lock orphelins, données corrompues) ; toujours SIGTERM d’abord, SIGKILL en dernier recours. Et chmod 777 « pour que ça marche » : vous venez de donner l’écriture à tous les utilisateurs du système — corrigez le propriétaire (chown) ou le groupe, pas les permissions du monde entier.

  • « df dit que le disque est plein, mais du ne trouve rien » — un processus tient ouvert un fichier supprimé : l’espace n’est libéré qu’à la fermeture. lsof | grep deleted, puis redémarrer le service fautif. Classique avec les gros logs supprimés à chaud.
  • Une variable non exportée n’existe pas pour les enfants — VAR=x reste locale au shell ; il faut export VAR=x pour qu’un processus lancé ensuite la voie. Source fréquente de « ça marche dans mon terminal, pas dans le service ».
  • sudo n’est pas un mot magique — relancer une commande échouée avec sudo sans comprendre pourquoi elle échouait crée des fichiers appartenant à root dans votre projet, et le vrai problème reste entier.
  • netstat est déprécié — l’outil moderne est ss (même usage : ss -tlnp), présent partout où netstat a disparu des images minimales.

Pour aller plus loin

  • MIT — The Missing Semester : le cours que toutes les écoles devraient donner (shell, outils, debugging)
  • explainshell.com : colle une commande, chaque flag est expliqué depuis les man pages
  • man7.org : les man pages de référence (signal(7), proc(5)…)
  • Julia Evans — Wizard Zines : les fanzines qui rendent strace, les signaux et les pipes limpides
  • Pratiquer : ouvrir un shell et explorer ls /proc/$$/ — le répertoire du processus… de votre propre shell

The essentials

Your servers run Linux. So do your Docker containers. Your CI, your Raspberry Pi, and 100% of the top 500 supercomputers. A developer who can find their way around a Linux shell debugs alone what others escalate — exactly what a recruiter looks for in an intern.

Two founding ideas structure the whole system:

  • Everything is a file — disks (/dev/sda), sockets, and even kernel state: /proc is a virtual filesystem where every process has its directory (/proc/1234/), where cat /proc/cpuinfo reads the CPUs and /proc/meminfo the memory. Read, write, redirect: one interface for everything.
  • Small composable tools — the Unix philosophy: each program does one thing well, text is the universal interface, and the pipe | assembles them into powerful chains. grep can’t sort, sort can’t filter — together, they do log analysis.

How it works

Processes: fork, exec, signals

A new process is always born through fork() (the parent clones itself) usually followed by exec() (the clone replaces itself with the new program) — that’s how your shell launches every command. Each process has a PID; the very first, PID 1 (systemd), boots the system and adopts orphans.

You talk to processes through signals:

Signal#EffectCatchable?
SIGHUP1terminal closed / reload configyes
SIGINT2Ctrl+Cyes
SIGTERM15“terminate cleanly” (default of kill)yes
SIGKILL9immediate death, decided by the kernelno
SIGSEGV11invalid memory accessyes
SIGSTOP / SIGCONT19 / 18pause / resumeno / yes

SIGTERM vs SIGKILL, the nuance that matters: SIGTERM is a request — the process can close its connections, flush its buffers, save, then exit. SIGKILL never reaches it: the kernel removes it, with zero cleanup. That’s the exact protocol of docker stop: SIGTERM to the container’s PID 1, a 10-second grace period, then SIGKILL. An app that doesn’t listen for SIGTERM (or launched behind a shell that doesn’t forward signals) dies brutally on every deployment.

stdin, stdout, stderr and redirections

Every process starts with three numbered streams: standard input (0), standard output (1) and standard error (2). The shell can rewire them at will:

         stdin (0)             stdout (1)
keyboard ─────────▶ process ─────────▶ terminal
                       │
                       └─── stderr (2) ─────▶ terminal

cmd > out.log     stdout → file (overwrites; >> appends)
cmd 2> err.log    stderr → file
cmd > f 2>&1      both → f (order matters!)
cmd1 | cmd2       stdout of cmd1 → stdin of cmd2

The pipe is the centerpiece: it plugs one program’s output into the next one’s input, no intermediate file. A real case — find the IPs hammering your login endpoint:

grep "POST /api/login" access.log \
  | awk '{print $1}'   # extract the 1st column: the IP
  | sort               # uniq requires adjacent lines
  | uniq -c            # count occurrences per IP
  | sort -rn           # descending numeric sort
  | head -10           # top 10 most insistent IPs

💡 Reflex to show — the sort before uniq -c isn’t decorative: uniq only merges adjacent lines. Forgetting it produces wrong counts — the kind of detail that proves in an interview you’ve actually practiced.

Key concepts to master

  • rwx permissions — three triplets: owner, group, others. In octal: r=4, w=2, x=1. chmod 755 = rwxr-xr-x (executable by everyone, writable only by the owner); 600 = rw------- (private SSH key). sudo runs a command as root — a privilege to justify, not a reflex.
  • Environment variables & PATH — a key=value set inherited by child processes (export API_URL=…). PATH lists the directories where the shell looks for commands, in order — that’s why a local script runs with ./script.sh, and why which python clears up doubts.
  • systemd at a glance — the service manager: systemctl status nginx (state), start/stop/restart, enable (start at boot). Logs go through journalctl -u nginx -f (-f follows live).
  • The commands that save the day — grep -rn "pattern" . (search the code), find . -name "*.log" (find files), ps aux (running processes), ss -tlnp (listening ports and by whom), tail -f app.log (follow a log live), df -h (disk space), du -sh * (what takes the space), top/htop (CPU/RAM in real time).
  • SSH & keys — a public/private key pair replaces the password: the public key goes into the server’s ~/.ssh/authorized_keys, the private one never leaves your machine. Safer (nothing to brute-force) and scriptable (CI, deployments).

🎤 In an interview — “a server stopped responding, what do you do?” Unroll a method, not a list: (1) I get access — ping, then SSH; (2) top — CPU maxed out? out of RAM? a runaway process?; (3) df -h — full disk, the dumbest and most frequent cause; (4) ss -tlnp — is my service still listening on its port?; (5) systemctl status app then journalctl -u app -n 100 or tail -f on its logs — the error is almost always there. A structured approach beats ten recited commands.

In an interview

“SIGTERM vs SIGKILL?” — SIGTERM (15) requests a clean shutdown: the process can catch it to close connections and flush buffers. SIGKILL (9) is uncatchable: the kernel kills without cleanup. Bonus: docker stop sends SIGTERM, waits 10 s, then SIGKILL — hence the importance of handling SIGTERM in a containerized app.

“What does chmod 640 mean?” — Octal: 6 = rw- (owner), 4 = r— (group), 0 = --- (others). Read-write for the owner, read-only for the group, nothing for the rest of the world — typical for a config file holding secrets.

“How is a process created on Linux?” — Through fork(): the parent clones itself (same code, copied memory); then usually exec() replaces the clone’s image with the new program. The shell does fork + exec for every command, and wait() to collect the exit code.

“What is PATH for?” — It’s the ordered list of directories where the shell looks for an executable when you type a command without a path. First found, first served — hence the surprises when two versions of a tool coexist (which settles it).

“How do you read a service’s logs in production?” — systemd service: journalctl -u service-name -f (or -n 200 for the last 200 lines). Classic file: tail -f /var/log/app.log, filtered with grep. Container: docker logs -f, since the app logs to stdout/stderr.

Pitfalls & misconceptions

⚠️ The two toxic reflexes — kill -9 as a first move: the process dies without flushing or releasing its resources (orphaned lock files, corrupted data); always SIGTERM first, SIGKILL as a last resort. And chmod 777 “to make it work”: you’ve just granted write access to every user on the system — fix the owner (chown) or the group, not the whole world’s permissions.

  • “df says the disk is full, but du finds nothing” — a process is holding a deleted file open: the space is only freed on close. lsof | grep deleted, then restart the guilty service. Classic with big logs deleted while hot.
  • A non-exported variable doesn’t exist for children — VAR=x stays local to the shell; you need export VAR=x for a process launched afterwards to see it. Frequent source of “works in my terminal, not in the service”.
  • sudo is not a magic word — rerunning a failed command with sudo without understanding why it failed creates root-owned files in your project, and the real problem remains untouched.
  • netstat is deprecated — the modern tool is ss (same usage: ss -tlnp), present everywhere netstat has vanished from minimal images.

Going further

  • MIT — The Missing Semester: the course every school should teach (shell, tooling, debugging)
  • explainshell.com: paste a command, every flag explained from the man pages
  • man7.org: the reference man pages (signal(7), proc(5)…)
  • Julia Evans — Wizard Zines: the zines that make strace, signals and pipes crystal clear
  • Practice: open a shell and explore ls /proc/$$/ — the process directory… of your own shell

S'entraîner sur ce sujet → Practice this topic →