Categorie
Digital life

Cos’è Unix? Caratteristiche, storia e filosofia

Tempo di lettura stimato: 14 minuti

Negli anni sessanta iniziò a sentirsi la necessità di un sistema operativo che rispondesse alle esigenze dei programmatori, che fosse più innovativo e curato dei suoi predecessori.

In quel momento l’informatica passò dall’essere funzionale alle scienze a diventare una materia a sé stante.

Esplorando questa storia parleremo di come dalle ceneri di un progetto fallimentare nacque il sistema operativo più influente della storia informatica. Un sistema operativo che ha direttamente o indirettamente influenzato tutti i moderni sistemi operativi.

È la storia di Unix, e di come le sue caratteristiche e la sua filosofia avrebbero trasformato il software in una forma d’arte, e posto le basi per una delle più grandi rivoluzioni dell’informatica.

Da Multics a Unix

Il contesto storico

Negli anni settanta l’informatica era un campo in costante espansione, sebbene appannaggio di pochi pionieri. Il loro compito si limitava a tradurre algoritmi per portare problemi computazionali in un linguaggio comprensibile dalle macchine.

I computer erano perlopiù dei mainframe: dei calcolatori particolarmente grandi e molto potenti – almeno per l’hardware dell’epoca. I sistemi operativi avevano un funzionamento tanto primitivo quanto limitato, essendo costruiti per poter funzionare su memorie nell’ordine dei kilobyte.

Il prezzo dei mainframe era elevatissimo, e solo poche società – fra cui la celeberrima IBM – erano in grado di permettersi di costruirli e venderli a qualche università particolarmente all’avanguardia.

Il costo di queste macchine ne rendeva difficile l’utilizzo per la sperimentazione informatica. Infatti gli algoritmi sperimentali sono particolarmente instabili, e c’era bisogno che i computer restassero accesi costantemente per poter essere utilizzati dai ricercatori.

Inoltre, in assenza di personal computer, i mainframe mettevano a disposizione un sistema di time-sharing. Questo permetteva di condividere le risorse hardware di un solo grande computer, che poteva essere usato da più ricercatori tramite dei terminali.

Per questo se un programma sperimentale avesse portato al blocco del sistema operativo (system crash) avrebbe finito per ostacolare il lavoro di molti ricercatori.

Multics

In questo contesto i Bell Labs della AT&T, il MIT e la General Electric lavoravano a Multics (Multiplexed Information and Computer Services), un sistema operativo time-sharing per il mainframe GE-645. Tuttavia, Multics affrontò diversi problemi e finì per essere dismesso.

Il sistema divenne presto troppo grande, intricato e difficile da mantenere, così alla fine degli anni ’60 i Bell Labs ritirarono i loro ricercatori. Fra gli ultimi dei loro uomini a lasciare il progetto troviamo Ken Thompson e Dennis Ritchie.

Thompson e Ritchie hanno sviluppato Unix lavorando con un mainframe PDP-7, dalle capacità ridotte ma dal costo accessibile per le università
Ken Thompson, seduto davanti ad un PDF-11, al lavoro con Dennis Ritchie (Wikimedia Commons)

Questi iniziarono a lavorare ad un sistema operativo più piccolo, ispirato ai progressi compiuti da Multics ma tarato su un mainframe meno potente e costoso (il PDP-7). Il progetto, inizialmente senza nome, aveva funzioni molto basilari rispetto al monumentale Multics.

Era single-tasking, cioè poteva eseguire soltanto un programma alla volta. Inoltre era scritto in assembly, un linguaggio di programmazione che varia per ogni processore – era quindi difficile portare il sistema operativo da un’architettura ad un’altra.

Proprio perché, in opposizione a Multics, il nuovo sistema operativo di Thompson e Ritchie non vantava alcuna capacità di multi-tasking, Brian Kernighan propose il nome di Unics (Uniplexed Information and Computer Services), il cui spelling divenne Unix.

Notiamo che la scrittura Unix indica il sistema operativo e le sue varianti, mentre la scrittura UNIX fa riferimento a uno specifico marchio registrato.

L’evoluzione di Unix

Già in questa sua forma primitiva il nuovo sistema operativo presentava dei grandi benefici rispetto ai suoi predecessori: l’hardware per il quale era stato scritto aveva prezzi più contenuti rispetto a quello dei grandi mainframe, e così le università avrebbero potuto permettersi di acquistare computer a scopo di ricerca informatica.

Unix, infatti, nasce proprio come sistema operativo orientato alla ricerca nel campo della programmazione. Tuttavia durante i primi anni di sviluppo esso restò più che altro all’interno dei Bell Laboratories fino a raggiungere uno stadio di maturazione tale da poterlo rendere una valida alternativa anche commercialmente.

Unix nasce dal lavoro di Dennis Ritchie e Ken Thompson
Dennis Ritchie a destra con Ken Thompson, creatori di Unix (Wikimedia Commons)

Nel 1973 il sistema operativo venne riscritto interamente in C. Si trattava di un nuovo linguaggio di programmazione sviluppato da Dennis Ritchie per scrivere del codice che potesse funzionare su più piattaforme (“Write once, compile everywhere”).

Inoltre il kernel crebbe grazie all’implementazione del multi-tasking e di funzionalità di time-sharing per consentire un utilizzo da parte di più utenti da più terminali contemporaneamente. Nel 1975 la prima licenza di UNIX venne venduta all’Università dell’Illinois, avviando un periodo di adozione su larga scala.

Nel frattempo aumentarono le varianti di Unix, prime fra tutte System V della stessa AT&T e la Berkley Software Distribution (BSD), dalle quali hanno origine numerosi sistemi operativi Unix-like usati tutt’oggi.

La Filosofia Unix

Brevitas, Doctrina e Labor Limae erano tre principi fondamentali per gli scrittori ellenistici e latini. Questi tre termini indicano rispettivamente la “brevità“, ovvero la capacità di non andare oltre il necessario, la “dottrina“, ovvero la capacità di saper imparare e mettere a frutto i grandi insegnamenti del passato, e il “lavoro di limatura” ovvero la rifinitezza massima della lingua e dello stile.

In qualche modo è a questi principi a cui si sono inconsapevolmente ispirati Dennis Ritchie e Ken Thompson quando hanno scritto Unix. Questo sistema operativo fu capace di imporsi non solo come esempio di efficienza e politura del codice, ma come un vero e proprio canone per tutti coloro che in seguito si sarebbero dedicati alla scrittura di software.

L’impatto di Unix sul mondo della programmazione informatica è tale che tuttora si parla di “Filosofia di Unix”.

A partire dal 1975, con la Version 6 di Unix, il sistema operativo iniziò a diffondersi fuori dal Bell Labs
La Version 6 di Unix, la prima versione del sistema operativo ad avere larga diffusione fuori dai Bell Labs. Nell’immagine il sistema operativo è emulato (Wikimedia Commons)

Diversi programmatori hanno cercato di trovare la frase che meglio descrivesse il cuore di questo stile di programmazione. Oggi proveremo anche noi a riassumerla in qualche punto fondamentale, e a capire perché ancora oggi abbia un impatto così forte sulla programmazione.

I principi cardine della cosiddetta “unix philosophy” sono:

  • Tutto è un file;
  • Il filesystem è gerarchico;
  • I programmi devono essere modulari e unifunzionali.

Tutto è un file

Una delle cose che si sentono dire più spesso quando si ha a che fare con un sistema Unix o Unix-like è tutto è un file (“everything is a file”). Spesso non ci si concentra neanche troppo sul significato di questa espressione, e non a caso: è molto difficile cogliere l’importanza di questa scelta di design – specie se si è estranei al mondo della programmazione. Tuttavia il suo impatto invisibile è molto più grande di quanto non possiamo pensare.

Cos’è un file?

Un file è una sequenza o un flusso ordinato di byte. Quando per esempio apriamo in un blocco note un file PDF, PNG, EXE, HTML, o altro, ci appare davanti una sequenza apparentemente incomprensibile di caratteri.

In informatica ogni carattere è associato univocamente ad un byte – una sequenza di 8 bit, dove un bit è uno zero o un uno. Quindi se scrivo “A” sto dicendo al computer 01000001, mentre se scrivo il carattere “0” sto dicendo al computer 00110000.

Poiché non vi è alcuna differenza fra un byte e un carattere, possiamo immaginare tutti questi file come sequenze di byte.

Cosa significa che tutto è un file?

Tuttavia, ad un’analisi più attenta, ci accorgiamo che in informatica molte cose sono soltanto flussi o sequenze di byte.

Per esempio uno schermo è una lunghissima sequenza di byte, dove ognuno, invece che descrivere un carattere tipografico, descrive un colore.

Verso una cassa audio si muove un flusso ordinato di byte che descrivono un suono, e lo stesso accade per un microfono, ma il flusso ha direzione contraria. Anche un disco è una lunga sequenza di byte. Sarebbe quindi molto conveniente se noi potessimo scrivere un disco o disegnare una figura sullo schermo trattando questi esattamente come se fossero dei grandi file.

Anche il modo in cui due programmi comunicano fra di loro è una sequenza di byte. Immaginiamo che un programma A voglia comunicare ad un programma B due numeri da sommare.

Per farlo il programma A può inviare un flusso di byte all’altro programma che descriva questa richiesta, e il programma B dev’essere in grado di interpretarla. Sarebbe conveniente, quindi, se anche questo genere di comunicazione potesse essere trattata come una scrittura e lettura da file.

In Unix è esattamente questo che accade. Per un programma scrivere un file e scrivere una parte del disco o una parte dello schermo è la stessa identica cosa: sono tutti file, e per leggere e scrivere dei file il kernel mette a disposizione due funzioni, una per leggere e una per scrivere. Così non serve implementare una funzione per ogni tipo di scrittura, poiché ogni componente parla la lingua dei file.

Il filesystem gerarchico

Un filesystem è il modo in cui i file sono organizzati sul disco. Generalmente si presenta come una struttura ordinata di directories (cartelle) e file. Si noti che in Unix le cartelle sono tecnicamente dei file.

In generale un filesystem occupa un’intera partizione del disco, e, allo stesso modo, ad ogni partizione del disco corrisponde uno e un solo filesystem.

Come abbiamo detto prima tutto è un file, il che significa anche che tutto può essere individuato come un elemento all’interno del filesystem.

Possiamo immaginare il filesystem come un processo che spiega al sistema operativo come accedere ad un certo file in una partizione. Esistono numerosi filesystem – ext4, FAT32, NTFS, eccetera – e ognuno di questi svolge questa funzione in maniera diversa. Perché un sistema operativo sappia leggere un filesystem è necessario che questo sia supportato.

Cosa si intende per gerarchia unica?

In Unix i filesystem di tutte le partizioni sono unificati in un unico e più grande schema (“gerarchia unica”). Possiamo immaginarlo come delle radici di un albero.

Dalla base (“root del filesystem”) partono dei rami (“directories”, cartelle) che si ramificano a loro volta (“sub-directories”) e così via. Se inseriamo un disco che contiene dei file, esso avrà un suo filesystem. Per leggerlo, tuttavia ci serve attaccarlo (“montarlo”) da qualche parte nel filesystem principale.

Il filesystem nei sistemi Linux è organizzato gerarchicamente come in Unix
Il filesystem dei sistemi Linux segue la gerarchia unica (Wikimedia Commons)

Possiamo creare una cartella vuota e attaccare il nuovo filesystem in quel punto, così che la sua root coincida con la cartella vuota. In questo modo tutto il nostro computer è accessibile tramite un unico grande e dinamicamente espandibile filesystem. Ogni programma può accedere facilmente ad ogni parte del sistema come se avessimo un unico disco con un’unica partizione, senza che ci sia bisogno che i programmi sappiano in che drive si trova un determinato file.

Questo non avviene in sistemi operativi come Windows, in cui non tutto può essere trattato come un file – quindi non possiamo accedere all’hardware come se fosse un semplice stream di dati alla stregua di un file. Non possiamo neanche ignorare in quale drive (C:, D:, E: eccetera) si trovi un determinato file, poiché ogni partizione con il suo filesystem è rigorosamente separata dalle altre.

Modularità

Come abbiamo già visto in Unix tutti i programmi parlano fra loro in un’unica lingua: la lingua dei file. Questa comunicazione è molto efficiente e dà un grande potere al programmatore.

Ken Thompson, il principale autore di Unix, notò che nel suo sistema operativo era possibile mettere in comunicazione due programmi in un modo semplice. Era possibile prendere l’output del primo programma e, sfruttando un file virtuale, usarlo come input per il secondo programma.

Il file virtuale doveva fungere da “condotto” (pipe) attraverso cui far scorrere questo flusso di dati da un programma ad un altro. In questo modo diventava possibile comporre assieme i programmi come fossero mattoncini della LEGO.

Si sarebbero potuti creare tanti programmi specializzati, ognuno capace di svolgere bene una specifica attività. Unendoli si sarebbero creati software via via più complessi, che avrebbero quindi fatto affidamento su piccoli programmi ben curati e molto stabili.

Questa semplice intuizione sarebbe diventata uno dei cardini della filosofia Unix. Il meccanismo di composizione dei programmi venne implementato nativamente nel sistema operativo e ne divenne uno dei suoi grandi punti di forza.

Un esempio pratico: comporre un nuovo programma

Immaginiamo di avere un programma che stampi il contenuto di un file (cioè che lo mostri sul nostro terminale). E immaginiamo che questo programma venga chiamato utilizzando il comando cat file.txt

Immaginiamo poi di avere un programma capace di rendere maiuscole tutte le lettere minuscole, e che sia utilizzato col comando awk { print tolower($0) }

Immaginiamo, infine, di avere un programma capace di stampare solo le righe che contengono una certa parola, e che sia chiamato col comando grep "parola"

In Unix per tradurre i comandi di un utente in azione scriviamo quei comandi nella shell. Separando dei comandi con il simbolo ‘|‘ possiamo usare l’output del precedente come input del successivo. Quel simbolo indica quindi il condotto (pipe) che collega i due programmi.

Ma allora, possiamo immaginare di inserire nella shell il seguente comando:

$ cat Le_mille_e_una_notte.txt | awk { print tolower($0) } | grep "CAMMELLO"

Abbiamo in sostanza creato qualcosa che prima non esisteva: un software capace di trovare ogni ricorrrenza di una parola in un testo. Così, anche un utente inesperto può comporre dei semplici programmi per creare qualcosa di più sofisticato.

Questo è uno dei grandi benefici di Unix rispetto ai sistemi del suo tempo e rispetto a molti sistemi operativi odierni.

La questione della licenza di AT&T

Nel 1956, a seguito di un accordo stragiudiziale, ai Bell Labs fu vietato di operare in ogni settore che non fosse quello delle telecomunicazioni. Le cose cambiarono negli anni ’70, ma per molto tempo questo impedì alla AT&T di distribuire una propria copia di Unix.

Tuttavia, la AT&T poté continuare a profittare dalla vendita delle licenze.

Come già accennato nel 1975 la prima licenza venne venduta all’Università dell’Illinois. Fra la seconda metà degli anni settanta e la prima metà degli anni ottanta Unix conobbe una forte espansione, anche grazie alla nascita della Berkley Software Distribution (una versione modificata di Unix).

Sempre in questo periodo la AT&T riuscì, a seguito di accordi, a distribuire la propria versione di Unix: nacque così System V, la più riconoscibile distribuzione di Unix.

Le licenze che la AT&T vendeva sono passate alla storia per essere particolarmente restrittive: infatti esse limitavano notevolmente le possibilità di utilizzo di Unix. Alcune consentivano prezzi sufficientemente bassi ma vincolavano l’uso del sistema a scopi educativi o accademici e, con il passare del tempo, le limitazioni divennero ancora più severe.

L’eredità di Unix

Anche per questo nel 1982 un programmatore di nome Richard Stallman iniziò a lavorare ad una versione libera e gratuita di Unix, che non avesse alcun tipo di restrizione e che potesse portare ad ogni utente i benefici di questo sistema operativo.

Tale sistema operativo fu chiamato GNU (GNU’s Not Unix, cioè GNU non è Unix) e assieme al kernel Linux ha dato vita alla famiglia di sistemi operativi GNU/Linux.

Richard Stallman ha dato via al progetto GNU
L’attivista e hacker statunitense Richard Stallman nella foto utilizzata per la copertina del libro biografico Free as in freedom (Wikimedia Commons)

In seguito anche BSD iniziò a rimpiazzare il codice originario proveniente dal Research Unix dei Bell Labs con del proprio codice, riuscendo così a distribuire Unix con una licenza estremamente più permissiva.

Oggi sono numerosissimi i sistemi operativi derivati o dirittamente ispirati a Unix. Si tratta dei cosiddetti sistemi Unix-like.

Essi nascono perlopiù dal lavoro di Stallman e dei numerosissimi altri programmatori che hanno lavorato con lui – i sistemi operativi GNU/Linux -, oppure sono derivati della Berkley Software Distribution. In questo secondo gruppo rientra il sistema operativo della Apple, macOS, ma anche altri sistemi operativi ad uso commerciale o open source – come rispettivamente Solaris e FreeBSD.

Brian Kernighan, uno dei protagonisti della nascita di Unix, ha dichiarato che se la politica della AT&T fosse stata meno restrittiva per quanto riguarda le licenze forse oggi non ci sarebbe stato bisogno dell’open source.

La mentalità di quell’epoca era troppo lontana da quest’idea per poterla anche solo concepire, poiché le compagnie che sviluppavano il software non avevano alcun interesse a fornire gratuitamente i loro prodotti. Sebbene, quindi, quest’idea fosse ben lontana dagli obiettivi del team di sviluppatori dei Bell Labs, in fondo è anche grazie a loro che oggi possiamo tutti quanti utilizzare liberamente i nostri computer.

Spezzone di un video promozionale dei Bell Labs in cui Ken Thompson e Dennis Ritchie spiegano le caratteristiche di UNIX

Sitografia

Di Giovanni Zaccaria

Giovanni Zaccaria collabora dal 2019 al progetto Polimathes.

Le sue più grandi passioni sono l'informatica e la programmazione, ma ha anche potuto interessarsi di linguistica e allo studio della lingua sanscrita.