Cette démo d’Unix vieille de 43 ans fonctionne encore telle quelle aujourd’hui

cet article a principalement pour but de pouvoir m'auto citer pour une proposition d'article auprès d'une revue de design

Pourquoi UNIX ?

En 1982 le service des relations publiques de Bell Labs commande une vidéo à la société de production EWB Productions. Cette vidéo présente l’une des productions phare du laboratoire, le système d’exploitation Unix. Le système a alors déjà 13 ans et est utilisé quotidiennement dans le laboratoire. La vidéo présente l’adaptation du logiciel aux nouveaux besoins de ces utilisateurices comme l’enjeu majeur du développement logiciel, contrairement à la conception de biens matériels :

When you build hardware and send it out, you may have to fix because it breaks but you don’t demand for example that your radio suddenly turns into a television.

Il est donc nécessaire de pouvoir modifier facilement et fréquemment le logiciel pour l’adapter aux besoins. Deux solutions sont proposées : 1. écrire du code d’une manière qui soit très claire, structurée et facile à modifier. 2. écrire de nombreux petits modules de code de façon à n’avoir à jeter ou modifier que quelques modules à la fois plutôt que de jeter “des milliers et milliers de lignes de code à la fois”1.

Si vous vous êtes déjà retrouvé·es bloqué·es par un·e fan d’Unix dans une longue conversation au sujet de son élégance vous reconnaitrez que la solution retenue par Bell Labs est plutôt la seconde. La stratégie est alors de rédiger ces petits modules et de faire manipuler ces primitives aux développeureuses de façon à ce qu’iels évoluent dans un niveau d’abstraction plus élevé, plus expressif, qui mènera à moins de code écrit et donc potentiellement moins de code à modifier/jeter.

Les primitives, blocs d’assemblage

Brian W. Kernighan, l’un des chercheurs les plus impliqué dans la création d’Unix et co-auteur avec Denis Ritchie du premier bouquin sur le langage C, embraye sur un ressenti toujours d’actualité : le logiciel semble passer le plus clair de son temps à nous compliquer la tâche plutôt qu’à la faciliter. Selon lui pour remédier à ce problème il faut des logiciels de “haut-niveau” faciles à manipuler et à combiner ensemble2. Dans le visuel suivant ce sont les utilitaires :

Une représentation en 3D de trois cubes inscrits les un dans les autres, avec
une esthétique très "début du graphisme 3D par ordinateur". Le cube du centre
est le "kernel", c'est à dire le noyau, le cube du milieu est le shell et le
cube le plus à l'extérieur sont les utilitaires.

Ces logiciels, qu’il décrit comme des blocs à assembler, sont les modules auxquels la vidéo faisait référence au début. Pris isolément ils ne font pas grand chose d’intéressant mais Unix propose une abstraction permettant de les combiner entre eux pour faire émerger de nouvelles fonctionnalités. Et c’est là que notre démo entre en jeu.

La démo

Un graphique présentant le fonctionnement de la démo. Quatre boites disposées
verticalement se succèdent, liées par des flèches allant de haut en bas.

Cette image montre à gauche le début de l’enchainement des utilitaires et à droite les fonctions qu’elles remplissent. On prend le contenu dans le fichier texte sentence, on le déplie pour avoir une ligne par mot, on met tout en minuscule, on trie par ordre alphabétique, on supprime les doublons et on compare le résultat avec un dictionnaire anglais. Dans la vidéo Kernighan utilise cette commande :

makewords sentence | lowercase | sort | unique | mismatch

Le caractère | étant la manière de combiner les commandes. Elle lie les primitives les unes avec les autres sur le modèle “le résultat de la commande à gauche devient l’entrée sur laquelle celle de droite opère”. Si l’on visualisait le résultat à chaque étape cela donnerait :

Le contenu d'origine :

At Bell Laborotories
UNIX systems privide
more timesharing ports
than all other systems
combined

makewords sentence | lowercase   | sort         | unique        | mismatch
|                    |             |              |               |
v                    v             v              v               v
At                   at            all            all             laborotories
Bell                 bell          at             at              privide
Laborotories         laborotories  bell           bell            timesharing
UNIX                 unix          combined       combined        unix
systems              systems       laborotories   laborotories
privide              privide       more           more
more                 more          other          other
timesharing          timesharing   ports          ports
ports                ports         privide        privide
than                 than          systems        systems
all                  all           systems        than
other                other         than           timesharing
systems              systems       timesharing    unix
combined             combined      unix

Il se trouve que l’on peut très facilement, en 2026, 43 ans plus tard, reproduire la démo à l’identique (je viens d’exécuter ça sur mon PC, svp croyez moi, les personnes ayant assisté à cette présentation sont témoins) :

makewords sentence | lowercase | sort | uniq | mismatch
laborotories
privide
timesharing
unix

J’ai contacté Kernighan par mail pour lui demander ce qui se cachait derrière les commandes makewords, lowercase et mismatch. Voici sa réponse :

Some (most?) of the commands in that pipeline were existing commands, just renamed to be more intuitive to someone who hadn’t seen it before. So “mismatch” is comm with the right arguments, “makewords” was probably tr with arguments, and so was lowercase.

Kernighan décrit ici le concept expliqué par Lorinda Cherry3 à partir de 15m37s dans la vidéo. En résumé il est possible de créer une nouvelle commande toto en écrivant des commandes dans un fichier nommé toto. Si l’on tente d’exécuter le fichier le système va le lire et exécuter les commandes à l’intérieur. On encapsule ainsi une ou plusieurs commandes dans une autre, pour des raisons sémantiques par exemple.

Puisque le texte source est en ascii4 je parierai sur le fait que makewords est en réalité une encapsulation de tr ' ' '\012'56, lowercase serait tr A-Z a-z et mismatch serait comm -23 - dict, dict étant le fichier contenant le dictionnaire7. La commande exécute donc en “réalité” ce qui suit, mais à la limite peu importe :

< sentence tr ' ' \012 | tr A-Z a-z | sort | uniq | comm -23 - dict

Cette facilité à reproduire un programme d’un langage haut niveau, 43 ans plus tard, à l’identique et sans avoir rien eu à installer ou bidouiller est à mon sens assez remarquable et l’une des raisons fondamentales pour lesquelles, malgré toutes ses limites, contraintes et étrangetés, je mise sur le shell Unix et ses primitives traditionnelles pour créer du logiciel durable. Le fait que ce système d’exploitation et ses primitives aient eu autant de succès est à la fois une malédiction, puisqu’elle force quiconque cherche à devenir familier ou familière avec la ligne de commande Unix à se farcir tout un tas d’incohérences et un modèle d’interaction figé dans le temps8, et une bénédiction puisqu’il rend cet environnement d’assez haut niveau très stable et pérenne, une immense partie de l’informatique en dépendant.

Stable, vraiment ?

Si le fait que l’écriture et le comportement de ces commandes n’aient pas changé est un constat intéressant en soit, s’arrêter là serait dommage. Les versions des commandes utilisées en 1982 et celles que j’utilise aujourd’hui ne sont pas les mêmes. D’un oeil extérieur sort et sort sont identiques mais le code a changé.

Je ne veux pas rentrer dans les détails pour cet article mais je jette en vrac des questions à creuser pour plus tard :

En 1982 sort faisait 900 lignes et la plus répandue aujourd’hui, celle des GNU coreutils, fait 4989 lignes. Plusieurs hypothèses pourraient l’expliquer. Du code doit être ajouté pour implémenter des algorithmes plus sophistiqués pour trier plus vite. Du code doit être ajouté pour faire usage de l’architecture plus complexe des processeurs modernes9. Des fonctionnalités ont été ajoutées (voir quelques paragraphes plus bas). Les primitives sont aujourd’hui distribuées toutes ensemble avec un certain niveau de factorisation de code entre elles permettant certainement d’économiser des lignes mais créant aussi du boilerplate. Les GNU coreutils ciblent une diversité bien plus grande d’architecture qu’Unix V7 etc.

La version de 1982 importe 5 .h de base, celle de GNU importe 34 .h.

Le sort de 1982 compile10 sur mon ordinateur faisant tourner debian 13 en 2026 avec la commande gcc --ansi sort.c mais termine directement avec un segmentation fault. Peut-être que le problème n’est pas complexe à résoudre, reste que la stabilité du C derrière notre pipe n’est pas garantie. Certainement parce que les librairies appelées par sort.c ont trop changé depuis.

L’ordinateur sur lequel Kernighan fait sa démo est incommensurablement plus lent que celui que j’utilise aujourd’hui. Le kernel Linux ne pourrait pas tourner dessus et donc certainement pas le sort d’aujourd’hui. A moins de précher pour une stabilisation complète des ressources en calcul dès 1982 ce n’est pas très raisonnable de reprocher au sort moderne de consommer plus de ressources. Une mesure plus intéressante serait de comparer, pour une métrique donnée, à quel point il est coûteux de faire tourner le sort du moment. Par exemple dans un article de blog Dan Luu remarque que le prix par unité de mémoire a baissé beaucoup plus vite que la taille des binaires et leur consommation en RAM11 et qu’il est donc un peu futile de se plaindre de cette croissance. sort a “grossi” mais il n’a jamais été aussi peu cher en mémoire de le faire fonctionner. Étudier cela sur le coût financier est une chose mais on pourrait peut-être se poser la même question pour un coût environnemental.

Toujours dans l’article de Dan Luu, il est montré que les commandes couvrent aujourd’hui beaucoup plus de fonctionnalités qu’auparavant, la quantité d’option servant de proxy pour la quantité de fonctionnalités. Le monde du terminal n’est donc pas entièrement immunisé contre ce phénomène. sort n’est pas renseigné dans l’article mais un exemple typique serait ls, commande listant des fichiers, étant passée de 11 options en 1979 à 58 en 2017, toujours pour lister des fichiers. Cette augmentation fait l’objet de débats enflammés dans la communauté Unix jusqu’à la création de sites dont le nom de domaine est une référence directe à l’une de ces controverses. Cela dit on constate que l’augmentation semble ralentir mais puisque les deux dernières dates auxquelles il a fait le calcul sont beaucoup plus rapprochées que les autres il est impossible de conclure. Refaire l’exercice pour 2026 pourrait permettre de confirmer ou infirmer l’hypothèse selon laquelle l’ajout d’option a atteint un plateau.

Annexes

Une seconde vidéo très similaire mais présentant des démos un peu différentes :


  1. ce qui n’est pas grand chose aujourd’hui mais représente beaucoup à l’époque. 

  2. je pense que les concepteurs d’Unix cherchaient fondamentalement à répondre aux mêmes problèmes que les chercheur·euses en IHM d’aujourd’hui. A ceci près que les interfaces répandues et les compétences d’une personne typique utilisatrice d’ordinateur de l’époque les ont pousser à concevoir une solution impliquant d’écrire du code haut-niveau dans un terminal là où aujourd’hui elle serait de concevoir une interface graphique intuitive. Pour reprendre un stéréotype éculé et problématique : “madame michu” existait déjà conceptuellement à l’époque mais on lui faisait invoquer une commande toute faite dans un terminal voir elle écrivait elle même sa commande avec quelques pipes. Les professionnels de l’informatique écrivaient du C pour construire les primitives de ces commandes. 

  3. co-autrice du Writer’s Workbench, un logiciel aidant à l’écriture de l’anglais incluant un mode de détection de mots jugés sexistes. Une démo datant de 1981 est consultable ici

  4. à l’époque sur de l’Unix c’était très très probablement le cas, je n’ai pas vérifié pour savoir si le système supportait d’autres encodages en 1982 mais il est possible que non 

  5. Et pas tr ' ' '\n' puisqu’étant donné la date l’Unix utilisé dans la vidéo est probablement Unix V7 et sa version de tr semble ne pas supporter l’écriture du caractère nouvelle ligne comme ‘\n’ mais supporte l’écriture en octal \012

  6. ou tr -cs A-Za-z'ICI-LITTERALEMENT-LE-CARACTERE-NOUVELLE-LIGNE-MAIS-JE-PEUX-PAS-LINSERER-PARCE-QUIL-EST-INVISIBLE' comme dans cet article comparant les solutions de McIlroy et Knuth a un problème de programmation. Ce duel est ensutie devenu légendaire depuis et souvent utilisé un peu à tort et à travers pour “prouver” la supériorité des pipes sur d’autres styles de programmation. La pipline de McIlroy commence d’ailleurs exactement comme celle de Kernighan dans la démo, seule la dernière commande est différente. 

  7. sur ma machine un dictionnaire anglais se trouve à /usr/share/dict/words 

  8. alors que tout un tas de bonnes idées et critiques ont émergé depuis. Voir par exemple ce blog qui en regorge. 

  9. un phénomène que Dijkstra expliquait déjà dans son discours The Humble Programmer en 1972. Il rendait compte de la manière dont cette complexité et puissance supplémentaire, allait faire du développement une pratique très complexe, capable de beaucoup, valant le coup d’être étudiée scientifiquement et donc associée à un certain prestige. Cela résonne particulièrement bien avec les travaux d’Isabelle Collet ou Felienne Hermans. La disparition des femmes de cette industrie qu’elles racontent coïncide chronologiquement avec la période évoquée par Dijkstra. D’ailleurs on notera qu’il désigne toujours le “programmer” au masculin, même pour parler de l’époque durant laquelle ce n’était pas un métier particulièrement genré. 

  10. avec des warnings que je n’ai pas pris le temps de corriger 

  11. cela dit rien ne garanti que cette tendance perdure, cf le prix de la RAM début 2026.