Partie 2 - Fichiers

Support présentation

Introduction

Dans les systèmes Unix/Linux, un fichier est une simple séquence d’octets enregistrée sur un périphérique de stockage. Le système ne connaît pas sa signification (texte, image, vidéo, binaire, base de données…). C’est le programme qui interprète les octets. Il existe cependant des standards de format (.png, .mp3, .mp4…) permettant à différents programmes de lire un fichier de la même manière, mais rien n’est imposé par le système. La commande file détermine le type de contenu.

Le principe fondamental d’Unix : « Tout est fichier ». Cela inclut :

  • fichiers classiques (texte, binaire, vidéo…),

  • répertoires (/home, /tmp…),

  • périphériques (clavier, disque, carte son…),

  • pipes (tubes),

  • sockets,

  • liens symboliques,

  • etc.

La plupart de ces objets peuvent être ouverts avec open puis manipulés avec les mêmes primitives système (read, write, close…). Il y a quelques exceptions : les répertoires se lisent avec opendir/readdir (et non avec read) et les sockets se créent avec socket (et non avec open), mais se lisent et s’écrivent ensuite avec read/write.

Sous Linux, les fichiers sont organisés sous forme de structure arborescente, commençant à la racine /. La commande tree permet d’afficher l’arborescence d’un répertoire :

$ tree -L 1 /
/
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib -> usr/lib
├── lib32 -> usr/lib32
├── lib64 -> usr/lib64
├── libx32 -> usr/libx32
├── lost+found
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── snap
├── srv
├── sys
├── tmp
├── usr
└── var

23 directories, 0 files
Résumé des différents répertoires sous la racine de Linux. Plus d'informations sur le site source.

Source de l’image.

Pour désigner un fichier, on distingue deux types de chemins :

  • absolu : commence à la racine / :

    • /home/user/file.txt,

    • /bin/bash.

  • relatif : dépend du répertoire courant :

    • ./file.txt (où . représente le répertoire courant),

    • ../autre.txt (où .. représente le répertoire parent).

Système de fichiers

Le système de fichiers (ext4, NTFS, FAT32…) définit l’organisation des fichiers sur le disque (le format des données). Il est pris en charge par un pilote qui fait partie du noyau.

Il gère :

  • les inodes, répertoires et blocs disque,

  • les permissions et métadonnées,

  • l’accès efficace et sécurisé aux fichiers,

  • la cohérence des données (journalisation, verrouillage…).

Chaîne d’accès

Lorsque votre programme veut lire un fichier, il appelle open. Le noyau associe alors le fichier à un descripteur de fichier (un int, voir Descripteurs de fichiers). Le programme utilise ensuite ce descripteur avec read, write, close…

Chaque appel traverse plusieurs couches avant d’atteindre le disque :

Du haut vers le bas : votre programme, la libc (facultative), les appels système, le système de fichiers virtuel, le pilote du système de fichiers, le pilote du disque, puis le disque. Le programme peut appeler directement les appels système sans passer par la libc.

Le système de fichiers virtuel (VFS) est une couche commune du noyau : grâce à elle, on utilise les mêmes appels (open, read, write…) quel que soit le système de fichiers (ext4, FAT32…) ou le type d’objet (fichier, périphérique, pipe…).

Exemples de systèmes de fichiers

Il existe de nombreux systèmes de fichiers, chacun ayant ses spécificités en termes de performances, fiabilité, compatibilité ou fonctionnalités.

Système

Système d’exploitation

Journalisé

Usage typique

ext4

Linux

oui

système par défaut de la plupart des distributions Linux

NTFS

Windows

oui

système par défaut de Windows

FAT32 / exFAT

tous (Windows, macOS, Linux)

non

clés USB, cartes SD, disques externes

APFS

macOS

oui

système par défaut de macOS (optimisé pour les SSD)

La journalisation consiste à noter les modifications dans un journal avant de les appliquer : après une coupure brutale, le système de fichiers peut retrouver un état cohérent.

Inodes

Un fichier est décrit par une structure interne, l”inode (index node, « inœud » en français), qui contient ses métadonnées :

  • type (fichier, répertoire, lien…),

  • taille (en octets),

  • droits d’accès (lecture/écriture/exécution),

  • propriétaire (UID) et groupe (GID),

  • dates : dernier accès (atime), modification du contenu (mtime), changement de l’inode (ctime) et, selon le système de fichiers, création (birth),

  • nombre de liens,

  • pointeurs vers les blocs disque.

Le nom du fichier n’est pas dans l’inode, il est stocké dans le répertoire qui le contient (voir Répertoires). C’est ce qui permet à un même inode d’avoir plusieurs noms (liens physiques).

La commande stat affiche les métadonnées :

$ echo "coucou" > mon_fichier.txt
$ stat mon_fichier.txt
  Fichier : mon_fichier.txt
   Taille : 7               Blocs : 8          Blocs d'E/S : 4096   fichier
Périphérique : fc01h/64513d Inœud : 17309649    Liens : 1
Accès : (0644/-rw-r--r--)  UID : (1000/user)   GID : (1000/user)
Accès : 2025-08-19 13:43:30.226795166 +0200
Modif. : 2025-08-19 13:43:30.227795178 +0200
Changt : 2025-08-19 13:43:30.227795178 +0200
  Créé : 2025-08-19 13:43:30.226795166 +0200
$ file mon_fichier.txt
mon_fichier.txt: ASCII text

Taille logique vs physique

Un fichier non vide occupe en général au moins un bloc disque (souvent 4 Kio). La taille logique (octets de données) peut être bien plus petite que la place réellement allouée.

Dans l’exemple ci-dessus avec stat, le fichier ne contient que 7 octets, mais occupe un bloc disque entier de 4 Kio (stat compte en unités de 512 octets : 8 × 512 = 4096).

Types de fichiers

Le type d’un fichier est visible avec ls -l : c’est le premier caractère de la ligne.

  • - : fichier régulier,

  • d : répertoire (directory),

  • l : lien symbolique (symlink),

  • c : périphérique caractère (terminal, clavier…),

  • b : périphérique bloc (disque dur…),

  • s : socket,

  • p : pipe nommé (FIFO).

Exemple :

$ ls -l /dev/null /bin/ls /
-rwxr-xr-x  1 root root 138216 févr.  8  2024 /bin/ls
crw-rw-rw-  1 root root   1, 3 août  18 09:33 /dev/null
...
drwxr-xr-x 169 root root 12288 août  18 10:08 etc
...

Droits des fichiers

Après le type, ls -l affiche les droits (permissions) du fichier. Il y a trois droits :

  • r (read) : droit de lecture,

  • w (write) : droit de modification,

  • x (execute) : droit d’exécution.

Ils sont donnés trois fois : pour le propriétaire, puis pour le groupe, puis pour les autres.

Ainsi :

  • rwxr-xr-x indique que le propriétaire a les droits de lecture, d’écriture et d’exécution, et que le groupe et les autres ont les droits de lecture et d’exécution,

  • rw-r--r-- indique que le propriétaire a les droits de lecture et d’écriture, et que le groupe et les autres ont seulement le droit de lecture.

La commande chmod permet de changer ces droits. La commande chown permet de changer le propriétaire et le groupe. Plus de détails dans le cours de Bash.

Descripteurs de fichiers

Chaque processus possède une table des descripteurs de fichiers, gérée par le noyau. Le noyau associe un entier (le descripteur) à une structure interne décrivant le fichier ouvert : la position courante dans le fichier (voir Position courante : lseek), le mode d’ouverture (lecture, écriture…) et l’inode du fichier. Le programme ne manipule que l’entier.

Trois descripteurs standards sont normalement ouverts au lancement :

  • 0 : entrée standard (stdin),

  • 1 : sortie standard (stdout),

  • 2 : sortie d’erreur (stderr).

<unistd.h> définit les constantes STDIN_FILENO, STDOUT_FILENO et STDERR_FILENO pour ces trois valeurs.

open renvoie toujours le plus petit numéro libre : le premier fichier ouvert par un programme a donc souvent le descripteur 3.

La table des descripteurs du processus contient 0 (stdin), 1 (stdout), 2 (stderr) qui désignent le même fichier ouvert (le terminal), et 3 qui désigne le fichier ouvert data.txt (position 0, mode O_RDONLY). Chaque fichier ouvert désigne un inode.

Ce mécanisme permet les redirections :

$ ls > out.txt       # redirige stdout vers un fichier
$ ls 2> err.txt      # redirige stderr
$ sort < data.txt    # lit sur stdin depuis un fichier
$ ls | grep '\.c$'   # pipe : stdout de ls vers stdin de grep

Répertoires

Un répertoire est un fichier spécial : c’est une table d’association entre des noms de fichiers et des numéros d’inodes (nom → inode).

L’option -i de ls affiche le numéro d’inode de chaque entrée (-a affiche aussi les fichiers cachés, -h affiche les tailles en format lisible) :

$ ls -laih
total 8,0K
18117141 drwxr-xr-x  2 user user 4,0K oct.  21 13:52 .
17301514 drwxr-xr-x 65 user user 4,0K oct.  21 13:52 ..
18117143 -rw-r--r--  1 user user    0 oct.  21 13:52 mon_fichier1.txt
18117145 -rw-r--r--  1 user user    0 oct.  21 13:52 mon_fichier2.txt

. est le répertoire lui-même et .. son parent.

Liens symboliques et physiques

Deux mécanismes Unix permettent d’accéder à un fichier par plusieurs chemins :

  • Lien physique (hard link) : un second nom (une seconde entrée de répertoire) pointant vers le même inode. Le fichier reste valide tant qu’au moins un lien existe.

  • Lien symbolique (soft link / symlink) : un fichier distinct (avec son propre inode) qui contient le chemin d’un autre fichier, comme un raccourci. Si la cible est supprimée, le lien devient cassé.

Commandes :

ln fichier_cible lien     # lien physique
ln -s fichier_cible lien  # lien symbolique

L’exercice p2e2 permet d’observer ces deux types de liens avec ls -li et stat.

Accès aux fichiers en C

En C sous Unix/Linux, il existe deux façons principales d’accéder aux fichiers :

  1. Avec la bibliothèque standard du C (libc, <stdio.h>) : fonctions de haut niveau et pratiques, bufferisées en mémoire utilisateur.

  2. Avec les appels système POSIX (<unistd.h>, <fcntl.h>) : fonctions de bas niveau, sans buffer (tampon en français) en espace utilisateur (le noyau garde son propre cache), proches du noyau, utilisées en interne par la libc.

Les valeurs de retour diffèrent selon les fonctions (NULL, EOF, -1…) : elles sont précisées pour chaque fonction ci-dessous. Il n’y a pas d’exception en C : il faut tester la valeur de retour de chaque appel. En cas d’erreur, il vaut mieux afficher la cause avec perror.

Bufferisation

La bufferisation stocke temporairement les données dans un buffer pour réduire le nombre d’appels système et améliorer les performances. C’est comme attendre d’avoir un sac plein avant de sortir la poubelle, plutôt que d’y aller pour chaque déchet.

Avec la libc, fprintf copie les données dans un buffer situé dans la mémoire du programme. Elles ne sont transmises au noyau (par un write) que lorsque le buffer est vidé :

  • appel à fflush ou à fclose,

  • fin normale du programme (return du main ou exit),

  • buffer plein,

  • fin de ligne (\n) si le flux est un terminal.

Avec un appel système, write transmet les données au noyau immédiatement.

À gauche, fprintf copie les données dans le buffer de la libc, dans la mémoire du processus ; un write les transmet au noyau quand le buffer est vidé. À droite, write transmet les données au noyau immédiatement. Le noyau écrit ensuite son cache sur le disque. Si le programme plante, le buffer de la libc est perdu.

Si le programme plante (segfault, abort…), le contenu du buffer de la libc est perdu : un message écrit avec fprintf juste avant le plantage peut ne jamais arriver dans le fichier. Ce qui a déjà été transmis au noyau n’est pas perdu.

Libc (E/S bufferisées)

Note

E/S signifie Entrée/Sortie (en anglais I/O, pour Input/Output).

La manipulation via la libc se fait avec la structure FILE (flux, stream) qui encapsule un descripteur de fichier noyau, un buffer, les états EOF/erreur, la position logique, etc.

 1 #define _POSIX_C_SOURCE 200809L // déclarations POSIX (voir la note plus bas)
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4
 5 int main(void) {
 6     FILE *f = fopen("data.txt", "w");
 7     if (!f) {
 8         perror("fopen");
 9         exit(EXIT_FAILURE);
10     }
11     fprintf(f, "Hello bufferisé !\n");
12     fclose(f);
13     return 0;
14 }

fopen et fclose (<stdio.h>) permettent d’ouvrir et de fermer un flux FILE :

FILE *fopen(const char *pathname, const char *mode);
int fclose(FILE *stream);
  • pathname : chemin du fichier

  • mode : mode d’ouverture

    • "r" : lecture (le fichier doit exister)

    • "w" : écriture (crée le fichier s’il n’existe pas, le vide en le tronquant à 0 octet s’il existe)

    • "a" : ajout en fin (crée le fichier s’il n’existe pas)

    • "r+" : lecture + écriture (le fichier doit exister)

    • "b" : modificateur « binaire » à ajouter au mode (ex. : "rb", "wb"), sans effet sous Linux/POSIX mais utile pour la portabilité (Windows)

  • stream : flux à fermer

fopen retourne un pointeur FILE *, ou NULL en cas d’erreur (errno indique la cause). fclose retourne 0, ou EOF en cas d’erreur (errno indique la cause).

Les autres fonctions de la libc et leurs équivalents POSIX (tableau Correspondance libc / POSIX) sont décrites dans les consignes des exercices et dans le man.

Appels système (E/S non bufferisées)

Les appels système manipulent directement des descripteurs de fichiers :

 1#define _POSIX_C_SOURCE 200809L
 2#include <fcntl.h>
 3#include <unistd.h>
 4#include <stdio.h>
 5#include <stdlib.h>
 6#include <string.h>
 7
 8int main(void) {
 9    int fd = open("data.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
10    if (fd == -1) {
11        perror("open");
12        exit(EXIT_FAILURE);
13    }
14
15    const char *msg = "Hello bas niveau !\n";
16    ssize_t n = write(fd, msg, strlen(msg));
17    if (n == -1) {
18        perror("write");
19        close(fd);
20        exit(EXIT_FAILURE);
21    }
22
23    close(fd);
24    return 0;
25}

Note

Les appels système utilisent quelques types définis par POSIX :

  • ssize_t : size_t signé, pour pouvoir renvoyer -1 en cas d’erreur (retour de read et write),

  • off_t : position (décalage) dans un fichier (utilisé par lseek),

  • mode_t : droits d’un fichier (ex. : 0644).

Note

Avec -std=c2x, le compilateur suit strictement le C standard : seules les déclarations du C standard sont garanties. Les en-têtes POSIX (<unistd.h>, <fcntl.h>…) déclarent les appels système les plus anciens (open, read, write…), mais pas forcément les autres fonctions et constantes POSIX (getline, symlink, ftruncate, nanosleep, O_CLOEXEC, O_DIRECTORY…). Les utiliser provoque alors une erreur de compilation (implicit declaration of function pour une fonction, undeclared pour une constante).

La macro _POSIX_C_SOURCE demande aux en-têtes (<stdio.h>, <unistd.h>, <fcntl.h>…) de déclarer toutes les fonctions et constantes de la version de POSIX indiquée. Les en-têtes la lisent au moment où ils sont inclus : on la définit donc en première ligne du fichier, avant tout #include :

#define _POSIX_C_SOURCE 200809L // utilise la version de 2008 de POSIX
#include <stdio.h>
// ...

C’est une bonne pratique : mettez cette ligne en tête de chaque programme C, même s’il compile sans elle (c’est ce que font les exemples complets du cours et les corrections des exercices).

Ouvrir et fermer : open et close

open (<fcntl.h> et <sys/stat.h>) ouvre un fichier :

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
  • pathname : chemin du fichier

  • flags : mode d’ouverture et options, les plus courants étant :

    • O_RDONLY (lecture seule), O_WRONLY (écriture seule), O_RDWR (lecture+écriture)

    • O_CREAT : créer le fichier s’il n’existe pas (nécessite mode)

    • O_TRUNC : tronquer à 0 octet si le fichier existe (avec écriture)

    • O_APPEND : écrire en fin de fichier

    • O_EXCL : échouer si le fichier existe déjà (à combiner avec O_CREAT)

  • mode : requis si O_CREAT (droits initiaux, en octal, affectés par le masque umask, voir Droits à la création : notation octale et umask ci-dessous)

Retourne un descripteur de fichier (entier >= 0, le plus petit numéro libre), ou -1 en cas d’erreur (errno indique la cause).

Ce ne sont pas deux fonctions (en C, deux fonctions ne peuvent pas porter le même nom) : open est une seule fonction à nombre variable d’arguments (..., comme printf), que le man présente sous ces deux formes. Le troisième argument n’est lu que si flags contient O_CREAT.

Les flags se combinent avec l’opérateur | (OU bit à bit) : chaque flag correspond à un bit d’un entier, et O_WRONLY | O_CREAT | O_TRUNC active les trois bits à la fois.

close (<unistd.h>) ferme le descripteur de fichier :

int close(int fd);
  • fd : descripteur à fermer

Retourne 0, ou -1 en cas d’erreur (errno indique la cause).

Écrire : write

L’écriture se fait avec write (<unistd.h>) :

ssize_t write(int fd, const void *buf, size_t count);
  • fd : descripteur du fichier dans lequel écrire

  • buf : adresse des octets à écrire

  • count : nombre d’octets à écrire

Retourne le nombre d’octets réellement écrits, ou -1 en cas d’erreur (errno indique la cause).

Le nombre d’octets écrits peut être inférieur à count (écriture partielle, par exemple si le disque est plein) : un programme robuste répète l’appel jusqu’à ce que tout soit écrit. La fonction write_full ci-dessous fait exactement cela (elle utilise errno, déclaré dans <errno.h>). Copiez-la dans vos programmes quand vous en avez besoin :

 1/**
 2 * Écrit exactement `count` octets de `buf` dans le descripteur `fd`,
 3 * en répétant les appels à write() si nécessaire (écritures partielles,
 4 * interruptions par un signal).
 5 * Retourne `count`, ou -1 en cas d'erreur.
 6 */
 7ssize_t write_full(int fd, const void *buf, size_t count) {
 8    const char *octets = buf;
 9    size_t total_ecrit = 0;
10    while (total_ecrit < count) {
11        ssize_t nb_ecrits = write(fd, octets + total_ecrit, count - total_ecrit);
12        if (nb_ecrits > 0) {
13            total_ecrit += (size_t)nb_ecrits;
14        } else if (nb_ecrits == -1 && errno == EINTR) {
15            continue; // interrompu par un signal avant d'écrire : on relance
16        } else {
17            // erreur, ou write a renvoyé 0 : on s'arrête (sinon la boucle
18            // pourrait tourner indéfiniment)
19            return -1;
20        }
21    }
22    return (ssize_t)total_ecrit;
23}

Lire : read

La lecture se fait avec read (<unistd.h>) :

ssize_t read(int fd, void *buf, size_t count);
  • fd : descripteur du fichier à lire

  • buf : buffer qui reçoit les octets lus

  • count : nombre maximal d’octets à lire (en général la taille de buf)

Retourne le nombre d’octets lus (> 0), 0 en fin de fichier (plus rien à lire), ou -1 en cas d’erreur (errno indique la cause).

Le nombre d’octets lus peut être inférieur à count : fin du fichier proche, pipe, terminal…

On ne sait pas à l’avance combien d’octets contient le fichier : on lit donc par morceaux, dans un buffer de taille fixe réutilisé à chaque tour, jusqu’à ce que read renvoie 0 :

1char buf[4096];
2ssize_t nb_lus;
3while ((nb_lus = read(fd, buf, sizeof buf)) > 0) {
4    // utiliser les nb_lus premiers octets de buf
5}
6if (nb_lus == -1) {
7    perror("read");
8}

Avertissement

read copie des octets bruts : il n’ajoute pas de '\0' à la fin. buf n’est donc pas une chaîne de caractères : printf("%s", buf) ou strlen(buf) liraient au-delà des octets lus (voir les chaînes de caractères). Utilisez le nombre d’octets lus (nb_lus), par exemple avec write(STDOUT_FILENO, buf, (size_t)nb_lus).

Position courante : lseek

Chaque fichier ouvert a une position courante (offset), gardée par le noyau : c’est le numéro du prochain octet qui sera lu ou écrit. Elle vaut 0 après open, et chaque read ou write l’avance du nombre d’octets lus ou écrits : deux read successifs lisent donc la suite du fichier, sans relire le début.

lseek (<unistd.h>) permet de déplacer cette position :

off_t lseek(int fd, off_t offset, int whence);
  • fd : descripteur du fichier ouvert

  • offset : décalage en octets (peut être négatif)

  • whence : point de départ du décalage

    • SEEK_SET : la position devient offset (compté depuis le début du fichier)

    • SEEK_CUR : la position avance de offset octets (ou recule si offset est négatif)

    • SEEK_END : la position devient la taille du fichier + offset

Retourne la nouvelle position (en octets depuis le début du fichier), ou -1 en cas d’erreur (errno indique la cause).

Un fichier de 12 octets, de A à L. Après open, la position vaut 0. Après read de 4 octets (ABCD), elle vaut 4. Après lseek de 3 avec SEEK_CUR, elle vaut 7. Après read de 4 octets (HIJK), elle vaut 11. Après lseek de 0 avec SEEK_SET, elle revient à 0.

Avec O_APPEND, la position est replacée à la fin du fichier avant chaque write : les écritures s’ajoutent toujours à la fin.

Correspondance libc / POSIX

La libc utilise les appels système en interne : chaque fonction de la libc a un équivalent de plus bas niveau.

Opération

Libc (FILE *, bufferisé)

POSIX (descripteur int)

Ouvrir

fopen

open

Fermer

fclose

close

Lire des octets

fread

read

Lire une ligne

fgets, getline

pas d’équivalent (lire avec read puis chercher le \n)

Écrire des octets

fwrite

write

Écrire du texte formaté

fprintf, fputs

write (après avoir formaté le texte, par exemple avec snprintf)

Déplacer la position

fseek

lseek

Vider le buffer

fflush

pas de buffer côté programme

Droits à la création : notation octale et umask

Notation octale

Les droits r, w, x du propriétaire, du groupe et des autres sont présentés dans Droits des fichiers. En C, on les écrit en octal, avec un chiffre par catégorie (propriétaire, groupe, autres). Le 0 initial indique au compilateur que le nombre est écrit en octal : 0644 ≠ 644 (644 est un nombre décimal, qui donnerait des droits absurdes). Chaque chiffre est la somme des droits accordés : r = 4, w = 2, x = 1. Ainsi 0644 correspond à rw-r--r-- (6 = 4 + 2 = rw-, 4 = r--) et 0755 à rwxr-xr-x (7 = 4 + 2 + 1 = rwx, 5 = 4 + 1 = r-x).

Masque de création (umask)

Les droits donnés à open (ou à mkdir) ne sont pas forcément ceux qu’aura le fichier : le masque de création (umask) du processus retire certains droits à la création. Pour connaître le masque de votre terminal, tapez la commande umask (souvent 0022, parfois 0002).

Le calcul se fait chiffre par chiffre : on garde les droits demandés, sauf ceux présents dans le masque.

propriétaire

groupe

autres

droits demandés : 0666

6 = rw-

6 = rw-

6 = rw-

masque : 0022

0 = ---

2 = -w-

2 = -w-

droits obtenus : 0644

6 = rw-

4 = r--

4 = r--

Ce n’est pas une soustraction : on retire des droits, et un droit absent reste absent. Par exemple, avec 0755 demandé et le masque 0022, on obtient 0755 (le groupe et les autres n’avaient pas le droit w).

Les droits observés sur un fichier créé par vos programmes (stat, ls -l) dépendent donc du masque de la machine. Un programme peut changer son propre masque avec la fonction umask (<sys/stat.h>), à ne pas confondre avec la commande du même nom :

mode_t umask(mode_t mask);
  • mask : nouveau masque, en octal (par exemple 0022)

Retourne l’ancien masque (cet appel n’échoue jamais).

Le nouveau masque s’applique aux fichiers créés ensuite par le processus : on l’appelle donc avant open, par exemple umask(0022);.

Fichiers spéciaux

Sous Unix, certains fichiers n’ont pas de données réelles mais sont des interfaces système :

  • /dev/null : tout ce qui est écrit est jeté, lecture = EOF,

  • /dev/urandom : générateur pseudo-aléatoire,

  • /proc : expose des informations sur les processus et le noyau,

  • /sys : interface avec les périphériques.

Exemple :

$ cat /dev/null
$ head -c 16 /dev/urandom | hexdump -C
$ cat /proc/cpuinfo