Linux – comandi base e script bash

Rispondi
Avatar utente
beatrice
co-admin
co-admin
Messaggi: 81
Iscritto il: lun mar 23, 2020 10:58 pm
Reactions score: 0
Contatta:
apr 2020 27 03:30

Linux – comandi base e script bash

Messaggio da beatrice

Linux nasce come sistema operativo Unix-like a riga di comando, con una sua shell che andremo a descrivere in questo webinar, trattando anche i principali comandi.
Questo tutorial farà un’introduzione ai comandi e alla shell di Linux, trattando gli aspetti principali.
Cercheremo di fare una panoramica generale su che cos'è l'interfaccia a riga di comando di Linux e di altri sistemi Unix; in realtà vedremo quali sono le caratteristiche principali della sintassi del linguaggio di scripting della Shell bar.
Spiegheremo che cos'è la Shell Bash, vedremo le caratteristiche del prompt, quali sono i comandi di base che utilizzeremo durante questa presentazione, dopodiché ci concentreremo sulla sintassi dello scripting quindi a partire dalla struttura di un file di uno script alle principali operazioni che consentono effettivamente di effettuare delle automazioni di sistema su Linux è in ambienti unix in generale.
Shell bash in Linux
Cominciamo con la shell: bash l'acronimo di Bourne again Shall è un gioco di parole perché si tratta di un'implementazione in seno al progetto GNU della shell Bourne, che prende il nome dal suo autore Steven Bourne; è una Shell, quindi un'interfaccia riga di comando sviluppata nei laboratori Bell per la versione 7 di Unix.
Quando nacque il progetto GNU, una delle prime cose che fu necessario implementare ovviamente fu la scrittura di un’interfaccia utente e si pensò quindi di basarsi sul design della shell Bourne, ormai famosa e ampiamente utilizzata in ambito Unix; tale shell è un interfaccia a riga di comando (shell sta per conchiglia, ossia l’involucro esterno con cui il sistema operativo si interfaccia all’utente) che integra molte delle funzionalità presenti non soltanto nella allora Bourne Shell di Unix, ma anche in altre shell.
Una delle cose importanti da dire è che in ambiente Unix non c'era soltanto una shell ma varie shell con caratteristiche diverse tra loro.
Bash è ampiamente utilizzata in ambiente Unix, non soltanto su Linux: ad esempio l'emulatore di terminale di MacOS Apple fa girare bash; è possibile far girare basso su Windows esistono vari port sia dei software GNU che addirittura, di recente con Windows 10 e con il sottosistema di emulazione Linux, di intere distribuzioni è possibile installare alcuni dei programmi distribuiti per esempio con Ubuntu direttamente su Windows e avere quindi la shell Bash che gira anche in quell’ambiente.
Si tratta quindi di un’interfaccia a riga di comando ma è un’interfaccia a riga di comando avanzata, che dispone di alcune funzionalità molto utili ad esempio l'auto-completion: è possibile ottenere dei suggerimenti durante la digitazione in modo che non sia necessario digitare interamente i comandi che vogliamo eseguire; basta digitare alcune lettere e poi premere il tasto Tab per ottenere un elenco di possibili comandi che vogliamo utilizzare. Questa è una funzione molto utile perché il meccanismo dell'auto-completion di Bash consente di essere personalizzato e configurato per i vari comandi installati nel sistema, quindi non soltanto permette di digitare i nomi dei comandi a partire da alcune lettere, ma permette addirittura di espandere la riga di comando con la sintassi del particolare comando che vogliamo utilizzare.
Tra breve vi proporremo una demo.
Un'altra cosa importante è che permette di mantenere una History (.bash_history) dei comandi digitati precedentemente: spesso quando si lavora direttamente con l'interfaccia riga di comando sia la necessità di digitare più volte gli stessi comandi e a volte si tratta di comandi molto lunghi, quindi poterli “ripescare” facilmente nella History sicuramente è molto utile. In fase di amministrazione la History si può richiamare con i tasti freccia su e freccia giù della tastiera e di fatto viene salvata in un file che in ambiente Unix sta all'interno della directory utente dell'utente che stiamo utilizzando e che si chiama bash History.
Inoltre si tratta di un prompt che consente di eseguire più comandi contemporaneamente sia in modo sequenziale quindi uno dopo l'altro, sia in modo concorrente.
Linux, il prompt
Adesso passiamo a vedere l’interfaccia, che vediamo nella figura seguente, dove abbiamo una schermata in ambiente Windows su cui facciamo girare una macchina virtuale con Ubuntu server, ma in ambiente Linux non sarebbe diverso.
Immagine
Questo è il prompt dell'interfaccia di bash, che è il punto di ingresso dal quale è possibile digitare i comandi per interagire con il sistema. Anche la forma del prompt può essere configurata e può variare in base al sistema che stiamo utilizzando: in questo caso ad esempio Ubuntu sceglie dimostrare un prompt in cui c'è il nome utente separato dalla chiocciolina dal nome host della macchina (in questo caso, test) e poi il percorso relativo della directory corrente.
Su altri sistemi il prompt potrebbe non avere lo stesso formato; questa cosa può essere personalizzata proprio dalla configurazione di sistema.
Allora, come dicevano, la prima cosa è che bash supporta auto-completion, così possiamo utilizzare il tasto Tab per ottenere la lista dei comandi che iniziano per la lettera che viene digitata; ad esempio se scriviamo cia e premiamo Tab due volte possiamo ottenere l'elenco dei comandi che iniziano per cia (due volte perché abbiamo due comandi nella lista).
Supponendo di voler utilizzare il comando Calendar, per esempio posso continuare a scrivere cale e a quel punto premendo Tab una volta, poiché l'unico comando che inizia per le lettere cal è calendar. Bash aggiunge automaticamente il nome del comando e inserisce uno spazio e permette di continuare a scrivere. L’immagine seguente mostra alcuni esempi di utilizzo dell’auto-completion.
Immagine
Questo meccanismo è molto potente perché consente effettivamente di essere molto più produttivi e molto più rapidi rispetto a quando si scrivono i comandi direttamente, perché è sufficiente digitare alcune lettere puoi premere Tab.
Un'altra cosa che la shell permette è la History dei comandi digitati: premendo il tasto freccia su è possibile richiamare l'ultimo comando digitato precedentemente (in questo caso Clear) e continuando a premere la freccia su è possibile scorrere la lista in alto oppure premendo freccia giù per scorrere la lista in basso. La figura seguente mostra quanto spiegato.
Immagine
I comandi di base
Andiamo avanti e vediamo alcuni comandi di base che servono per navigare tra le Directory del file system, per modificare i permessi dei file che lavoreremo ed interagire con gli input e output dell' interfaccia a riga di comando. Di seguito elenchiamo i comandi essenziali per interagire con l'interfaccia utente; ovviamente questa è una lista riduttiva perché ce ne sono un'infinità.
 

  • cd

  • ls

  • chmod

  • echo

  • cat

  • kill

  • grep

  • man

 
L'ultimo forse il più interessante il comando man, che ci permette di ottenere una pagina di documentazione su un particolare comando direttamente dall’interfaccia.
Comunque procediamo per ordine e notiamo subito che ci sono delle analogie con altri sistemi operativi: per esempio sicuramente molti di voi intuiranno che il comando cd sta per Change Directory e quindi consente di spostarsi all'interno del file system, mentre il comando LS il comando lista consente di ottenere la lista dei file delle directory presenti nella Directory corrente.
Il comando chmod consente di modificare i privilegi e i permessi su un particolare file; a riguardo ricordiamo che in ambiente Unix ad ogni file sono associati dei privilegi di lettura, scrittura ed esecuzione, per l'utente proprietario, il gruppo dell’utente proprietario e per tutti gli altri. Con chmod è possibile modificare questi privilegi, naturalmente a patto che si sia in possesso del permesso o privilegio per poterlo fare.
Echo è un comando che consente di creare dell'output, ossia di scrivere delle stringhe sull’output della riga di comando; lo utilizzeremo negli esempi di scripting che vedremo a breve; invece cat è un comando che consente di concatenare più flussi in input, più file in input in un unico file o in un unico flusso di output.
Kill è un comando che serve per inviare dei segnali a un processo e tra questi segnali c’è quello di terminazione e quindi un comando che di solito viene utilizzato per esempio per terminare forzatamente l’esecuzione di un processo che si trova in background; vedremo poi un esempio di utilizzo.
Grat è un filtro un comando che consente di filtrare i dati In input e ottenere un set ridotto che secondo certi criteri di ricerca; infine, man consente di visitare le pagine della documentazione installata nel sistema.
In ogni momento è possibile abbandonare l’esecuzione di un comando con la combinazione di tasti Ctrl+C.
Vediamo quindi l’utilizzo di questi comandi e il risultato nella shell: nella figura sottostante abbiamo esempi di utilizzo del comando cd, che segue una sintassi nota e diffusa praticamente nella maggior parte dei sistemi operativi non soltanto su Unix, che vede l'utilizzo anche dei caratteri speciali del nome di directory speciale.
Immagine
In alto vediamo il comando per tornare dalla directory “esempi” alla directory Home dell'utente Sergio; se volessimo ritornare su esempi dovremmo digitare cd esempi.
Passiamo ad ls, che permette di ottenere la lista di file presenti nella directory da cui viene lanciato: nel caso proposto dall’immagine seguente ci sono alcuni script che sono dei piccoli esempi che vedremo nel corso di questa presentazione.
Immagine
Altri comandi come Eco Cat Kill saranno parte degli esempi di utilizzo, per cui li tratteremo direttamente lì nel momento in cui li incontreremo per la prima volta.
 
Sintassi dei comandi Linux
Soffermiamoci adesso sul comando man, che si utilizza in modo molto semplice: basta digitare man seguito dal comando del quale vogliamo leggere la documentazione: ad esempio se vogliamo sapere qualcosa sull’utilizzo di grep possiamo digitare man grep per ottenere la pagina di manuale secondo gli standard di Unix del comando grep (vedere immagine seguente).
Immagine
In realtà man utilizza una utility che si chiama more per la lettura, ovvero per mostrare a schermo la pagina, per scorrere la quale si possono utilizzare i tasti freccia, pagina su e pagina giù; per uscire e ritornare alla riga di comando basta digitare il tasto ESC.
Script bash
Allora, procediamo e andiamo subito nel vivo della struttura degli script; come accennato, bash è un’interfaccia a riga di comando: serve per interagire col sistema serve per dare dei comandi al sistema, ma una delle cose più potenti che consente di fare è la scrittura di piccoli programmi, ossia di piccoli script che permettono quindi di effettuare delle automazioni sul sistema.
Ma che cos'è uno script? Ebbene, non è altro che un elenco di comandi che eventualmente può utilizzare delle variabili, il tutto raggruppato in un unico file all'interno di un unico nome, quindi il vantaggio nell'utilizzare degli script è che tutte le volte che abbiamo la necessità di impartire tanti comandi effettuando delle scelte (per esempio delle scelte condizionali) ed eseguirne dei cicli dovendo ripetere diverse volte le stesse istruzioni, possiamo effettivamente programmare l'esecuzione di questi comandi in questo linguaggio di scripting.
Per chi conosce gli ambienti Microsoft, possiamo dire che l’equivalente in MS-DOS e Windows (da riga di comando) degli script sono i file batch (.bat) composti anch’essi da elenchi di comandi eseguibili con un solo comando.
Struttura di uno script
Passiamo ad esaminare la composizione degli script aiutandoci con l’immagine seguente, che mostra la struttura di uno script, il quale, come vedete, è una lista di istruzioni e quindi si può considerare un programma.
Immagine
La prima riga dello script di solito (ma non è obbligatorio che vi sia) è il cosiddetto hashbang o shebang: si tratta della sequenza #! quindi (ash bang, da qui il nome) seguito dal percorso eseguibile che interpreterà lo script: in questo caso /bin /sh. In realtà si tratta di un meccanismo già integrato in Unix negli anni ‘80 del secolo scorso e poi traslato per consuetudine; la possibilità di scrivere un file di testo che riporti il nome dell'interprete che lo eseguirà, permette di risolvere l'ambiguità nell'associazione tra script e interprete a livello di sistema.
Se fossimo in ambiente Windows avremmo la necessità di indicare l'estensione del file .bat per indicare che si tratta di uno script dell'interfaccia a riga di comando e che quindi va interpretato con CMD (come comando) o con l’estensione py se si tratta di un file che deve essere interpretato con l’interprete di Python. Invece in ambiente Unix non è necessario dare tale comunicazione tramite l'estensione ma la si può indicare direttamente nella prima riga dello script, quindi i file degli script bash di solito iniziano con uno shebang che punta su /bin /sh o su /bin /bash per esempio, ma analogamente uno script Perl inizierà con il percorso dell'interprete perl o un file Python comincerà eventualmente con l’indicazione dell' interprete Python.
La shell bash legge la prima riga dello script e invoca il programma interprete che effettivamente è stato indicato nella prima riga.
Dopo l’invocazione del programma interprete si possono inserire commenti, che nel caso dell’esempio in figura sono l’intestazione, che non è obbligatoria. Come si evince dal colore della syntax highlighting di questo esempio, i commenti si scrivono preceduti dal cancelletto, quindi anche l’hash bang è un tipo particolare di commento, ma non è un'istruzione che verrà eseguita: è solo una un metadato dello script. Il # indica quindi alla shell che ciò che segue non va eseguito ed è il corrispondente del // nel linguaggio di programmazione C.
Sebbene non necessario, è buona norma commentare alcune righe iniziali che spiegano cosa fa lo script, se appartiene ad una suite di programmi, chi ne è l'autore è una breve descrizione che indica anche eventualmente la licenza. Quello che trovate nell’esempio è uno script che fa parte del client di posta dell'ambiente KDE (kMail) ed è uno script che consente di invocare un antivirus (Sophos) e di decorare eventualmente i messaggi che secondo l'antivirus contengono dei virus con una stringa che vedete in rosso nell’immagine (X-virus-flag: Yes, X-virus-flag: No). Vedremo in seguito cosa significano esattamente queste istruzioni.
Dunque, la struttura prosegue poi semplicemente con l'elenco delle istruzioni riga per riga, che  verranno eseguite dall'interprete.
Notate che è possibile scrivere uno script iniziando direttamente con le istruzioni da eseguire, ma la struttura mostrata, che è una convenzione, effettivamente aiuta chi non ha scritto lo script a conoscerlo preliminarmente, perché aprendolo con un editor di testo si può vedere subito che cosa fa con la descrizione indicata direttamente dall'autore.
Inoltre è possibile richiamare altri script all'interno di uno script principale, qualora si voglia modularizzare uno script molto complesso; allo scopo si può utilizzare il comando:
source script
seguito dal nome del file; attenzione a definire i percorsi, ossia a scrivere quello da cui dev’essere invocato lo script.
 
Ridirezione dei flussi
Entriamo adesso nel vivo dei dell'esecuzione dei comandi in ambiente bash: uno dei meccanismi più potenti e quello della ridirezione dei flussi; per capire di cosa si tratta va detto che in ambiente Unix ad ogni processo sono associati tre flussi: un flusso di input e due flussi in uscita detti di output di errore. Tradizionalmente i programmi scritti in C in ambiente Unix utilizzavano questi tre flussi rispettivamente per ricevere input dall'ambiente esterno (associato a Standard Input, per default alla tastiera) per generale dell'output (per default Standard Output, associato al video) ed eventualmente per indicare delle condizioni di errore (Standard Error). Il motivo per cui gli output e i flussi di errore sono separati va ricondotto a quando Unix veniva utilizzato su mainframe a cavallo tra gli anni ‘70 e ’80 del secolo scorso e veniva utilizzato su macchine in cui possibilmente l’output veniva eseguito non solo su schermo ma anche su telescrivente; allora possiamo immaginare dei casi in cui potesse essere utile ricevere una condizione d’errore stampata su telescrivente e un output su display o viceversa.
Questa convenzione è rimasta fa parte dello slumber di programmazione del C e dello Standard Posix, quindi in generale si ritrova in ambienti Unix e Linux.
Quindi un comando, quando viene eseguito, riceve input dal suo standard input ed emette output sui suoi standard output o standard error; bash però ci consente di ridirigere questi flussi e quindi far sì che piuttosto che ricevere input da tastiera e piuttosto che emettere output sia normale che di errore su schermo, sia possibile intercettare questi flussi ridirigerli, ad esempio come visibile nell’immagine seguente, verso un file.
Immagine
Esiste una sintassi che si basa sui simboli di maggiore e minore in varie declinazioni che adesso vedremo e che consente di effettuare questa ridirezione: ad esempio un comando che genera output sul suo standard output (a schermo) può essere diretto con il comando 1> o semplicemente con > per fare in modo che l'altro invece venga scritto su File. L’immagine mostra un ampio ventaglio di casi con la relativa spiegazione. In linea generale il simbolo > dirige verso il file e il minore acquisisce da file.
Un comando che di solito si utilizza in Linux per ottenere l'elenco dei dispositivi connessi al bus PCI è:
lspci
seguito da Invio; tale comando stampa a video una lista di dispositivi installati sulla nostra macchina. È un esempio che mostra cosa accade quando viene invocato un comando che emette output; il suo standard output senza diversa specifica nella riga di comando è lo schermo: è lo standard output della console, quindi l’output viene mostrato a video (immagine seguente).
 Immagine
Ma se dopo il comando scriviamo > seguito da uno spazio e da un nome file, come ad esempio:
lspci > elenco.txt
a schermo non compare più nulla perché lo standard output viene ridiretto sul file specificato, quindi digitando il comando ls scopriamo che è stato creato un file elenco.txt, aprendo il quale vediamo che contiene la lista che altrimenti sarebbe andata sullo schermo.
Questo è un meccanismo estremamente potente perché consente di personalizzare l'esecuzione dei programmi e di controllare il flusso di input e di output senza dover modificare il funzionamento del programma stesso; in altri ambienti, per avere un programma che genera una lista di dispositivi connessi e la salva su file bisognerebbe modificare quel programma per far sì che crei un file e vi scriva il risultato delle elaborazioni invece con bash è possibile senza fare ciò.
On-line o nelle pagine di manuale trovate la specifica sintassi per ridirigere soltanto il flusso di output, solo il flusso di errore o entrambi, oppure ridirigere il flusso di input. È anche possibile fare il contrario: se c'è un comando che richiede un input da tastiera è possibile utilizzare il comando minore per far sì che l'input venga preso da un file piuttosto che dalla tastiera; ciò è comodissimo ad esempio per acquisire il contenuto di un file di testo.
Le pipe
Un'altra possibilità per redigere i flussi è offerta dalle pipe: la pipe è un altro meccanismo estremamente potente in bash che permette di combinare l'esecuzione di più comandi collegando l’output del comando precedente all’input del comando successivo. Questo consente, in un'unica riga, di effettuare delle elaborazioni concatenate; ciò perché tutto questo modello, un processo con tre flussi e quant'altro, segue la cosiddetta “filosofia dei filtri” cioè un programma è una scatoletta che riceve input per effetto delle elaborazioni ed emette un output.
Se torniamo all’immagine precedente, vediamo che in alcuni esempi abbiamo il comando >>; ebbene, qual è la differenza? La differenza consiste nel modo con cui il file viene creato: utilizzando > il file viene sovrascritto se esiste e il contenuto del file diventa l’output del comando, mentre con > > l'output del comando impartito viene “appeso” alla fine del file; riprendendo l’esempio fatto con
lspci > elenco.txt, impartendo il comando seguente:
lspci >> elenco.txt
e dando per scontato che il file elenco txt già esista, dopo l’ultima riga ci ritroviamo una copia dell’elenco dei dispositivi, ovvero il contenuto duplicato.
Per quanto riguarda la ridirezione dei flussi error, il discorso è analogo solo che anziché utilizzare > o 1> si utilizza il 2 per specificare l'altro flusso, perché ci sono diversi comandi che separano l’output che è andato a buon fine dalle condizioni di errore.
Per fare un esempio supponiamo per esempio che lspci non riesca per un qualsiasi motivo ad effettuare l'enumerazione dell'hardware perché il sistema non funziona correttamente; in tal caso genererebbe un messaggio di errore se abbiamo ridiretto lspci e ridiretto esclusivamente il flusso dello standard output su file, nel file non troveremo il messaggio di errore ma ci ritroveremo un file vuoto.
A volte può essere necessario separare questi due file per questioni di logging: per esempio potremmo ridirigere su due file diversi lo standard output e lo standard error, oppure ridirigere solo lo standard error per avere un log di errore nel caso in cui ci sia stato un errore e un file vuoto nel caso in cui l'esecuzione sia andata a buon fine; questo è il meccanismo che viene utilizzato di solito in ambienti Unique
Ritorniamo alle pipe, le quali, come accennato, permettono di combinare due programmi: l’immagine seguente mostra il carattere utilizzato, ossia la barra verticale che su tastiera con layout italiano si trova a sinistra del tasto 1 e che quindi si fa con lo Shift, per creare una pipe.
Immagine
In linea generale nella sintassi della pipe lo standard output del comando a sinistra della barra verticale viene connesso allo standard input del comando alla destra.
Per fare un esempio scriviamo:
# ls -l | grep “sh”
dove il comando ls è in pipe con grep. Se impartiamo ls senza alcun parametro otteniamo la lista di tutti i file, mentre se digitiamo ls in pipe a grep sh, grep filtra quello che fa ed elabora le linee in input e restituisce in output soltanto le linee che rispondono al criterio di ricerca; in questo caso il criterio di ricerca (che è il testo virgolettato) dice a grep di restituire l’elenco di file che contengono sh.
C'è da dire che in realtà ls consente di effettuare già questo tipo di filtraggio, ma l’esempio è servito a mostrare quello che succede quando due comandi vengono concatenati tramite pipe.
Un altro esempio potrebbe essere l’utilizzo del comando echo, che permette di dare in output quanto scritto tra virgolette a seguire; se scriviamo:
echo “stringa di prova”
seguito da Invio, produce nella linea seguente la scritta stringa di prova.
Se invece digitiamo:
echo “stringa di prova” | grep “prova”
il video restituisce stringa di prova perché il comando grep ha trovato una linea che risponde al criterio di ricerca.
Notate che se avessimo usato lo stesso comando del caso precedente:
echo “stringa di prova” | grep “sh”
avrebbe restituito un output vuoto.
Da notare che bash supporta anche la colorazione dell'output da riga di comando e il sistema è configurato per far sì che possa restituire un output colorato per evidenziare il match della stringa di ricerca, quindi in questo caso prova verrebbe mostrato in rosso.
Variabili in bash
Ogni linguaggio di scripting che si rispetti deve poter permettere l'utilizzo di variabili; senza entrare nei dettagli della programmazione, precisiamo che se vogliamo personalizzare l'esecuzione di uno script ci troveremo di fronte all'esigenza di definire degli elementi variabili, del dei nomi dei placeholder per dei valori che cambieranno in base alle esecuzione dello script.
In bash le variabili possono essere sia d’ambiente, sia predefinite.
Le variabili nella sintassi di scripting di bash si dichiarano semplicemente con l'uguale, quindi basta indicare il nome della variabile, digitare il simbolo uguale e poi indicare il valore che si vuole assegnare alla variabile stessa:
nome_variabile=valore
Per effettuare una dichiarazione, un'assegnazione o per accedere al valore di quella variabile, si utilizza il nome della variabile preceduto da dollaro e cioè possibile non soltanto negli script, ma anche nella riga di comando: ad esempio esistono delle variabili d'ambiente come $path, che restituisce in output il contenuto della variabile path, che in questo caso contiene una serie di directory separate da due punti (si tratta delle directory dov'è possibile trovare dei file eseguibili e quindi fanno parte della path. La lettura si effettua con:
$nome_variabile
È possibile elencare a video le variabili d’ambiente mediante il comando env seguito da Invio.
Prestate attenzione al fatto che i nomi di variabile sono case sensitive ($USER e $user sono due cose diverse!).
Notate che si può assegnare a una variabile l’output di un altro; questo in ambiente Unix si faceva con l’apice inverso, ma non si tratta dell’apice che trovate sulla tastiera (quello a destra dello zero) ma si tratta di un simbolo che va digitato in ambiente Linux (in Windows si ottiene con Alt+096). La sintassi oggi utilizzata utilizza il dollaro e le parentesi al posto dell’apice inverso.
L’assegnazione del valore di ritorno di un comando si ottiene con il carattere apice inverso  (backtick) che si digita con AltGR + ì su Linux / Unix oppure con ALT + 096 su Windows.
Ad esempio:
a=ls
Per evitare di dover digitare, quando dobbiamo invocarlo, il percorso completo di ogni eseguibile,  utilizziamo il carattere dollaro ($).
Le variabili predefinite in bash sono:

  • da $0 a $9 (argomenti della riga di comando dello script);

  • $# (numero di argomenti passati allo script);

  • $$ (PID assegnato allo script);

  • $USER (nome dell’utente che ha eseguito lo script);

  • $HOSTNAME (nome host della macchina).

 
Quanto alle variabili predefinite, sono disponibili all'interno degli script; ad esempio le variabili che contengono i valori degli argomenti.
È possibile richiamare uno script non soltanto richiamando il suo nome, ma anche fornendo dei valori sulla riga di comando, come avviene ad esempio per il comando echo, cui segue quello che vogliamo scriva: la stessa cosa può avvenire per gli script, ossia possiamo invocare uno script passando un argomento.
I primi 10 argomenti sono accessibili con le variabili che vanno da $1 a $9; $# ci dice quanti argomenti sono stati passati, $$ è l'identificativo del processo associato allo script e poi ci sono delle variabili come $USER e $HOSTNAME. Ad esempio Echo $USER restituisce il nome utente corrente.
Il valore di una variabile può essere concatenato ad una stringa di testo; ad esempio:
echo “Il tuo nome utente è $USER”
Controllo di flusso in bash
Impossibile affrontare di programmazione di scripting senza vedere le strutture di controllo, la prima delle quali è il controllo di flusso: in molti casi capita di dover effettuare un’esecuzione condizionale, cioè di dover eseguire un comando in base al fatto che sia verificata o meno una condizione; questo è possibile, in bash, con il costrutto if.
Il costrutto if, alla stregua di altri linguaggi di programmazione si compone di due parti, una contenente i comandi che verranno eseguiti solo a condizione verificata (se vera) e l'altra (quella dopo else) che verrà eseguita qualora invece la condizione sia falsa. If ed else significano, rispettivamente, se e altrimenti. Then indica cosa di fa dopo l’if.
La sintassi è quella mostrata qui di seguito:
if [ -e “/tmp/prova” ]
then
echo “Il file prova esiste”
else
echo “Il file prova non esiste”
fi
Tra parentesi quadre si fa una valutazione di condizione: nell’esempio, il trattino significa esiste e tra virgolette abbiamo un percorso, quindi la condizione è che esiste il percorso /tmp/prova: se esiste otteniamo a video la scritta Il file prova esiste, altrimenti Il file prova non esiste.
Il costrutto if, come altri nella sintassi bash, si chiude con il suo nome al contrario (fi).
Il costrutto deve essere scritto in un file .sh, eseguendo il quale va in esecuzione; il file inizia sempre con #! /bin/bash.
L’esecuzione si ottiene scrivendo al prompt il percorso completo dove è salvato il file o, se siamo già nella Directory che lo contiene, utilizzare il relativo percorso
./nomefile.sh
Esistono tantissime altre condizioni per l’if: ad esempio verificare se una variabile è maggiore o minore di un'altra e così via; rimandiamo, chi volesse approfondirle, alla documentazione on-line.
I cicli in bash
Un altro costrutto importante nella programmazione è dato dai cicli; bash ne contiene diversi e qui conosceremo il ciclo while e il ciclo for, che sono gli stessi della programmazione, ad esempio in linguaggio C.
Si tratta di due costrutti che consentono di ripetere un certo blocco di istruzioni contenute al loro interno un certo numero di volte: il ciclo while permette di ripetere il blocco di istruzioni al suo interno fintantoché una condizione sia verificata, mentre  il ciclo for si limita a iterare una lista o un intervallo di valori. Un esempio di ciclo while è: 
while [ -e “/tmp/prova” ]
do
    echo “In attesa che il file venga cancellato...”
    sleep 5
done
echo “File prova cancellato.”
Il ciclo va scritto in un file .sh, che possiamo chiamare, ad esempio, attesa.sh.
La sintassi del ciclo while prevede la definizione della solita condizione (qui è la stessa vista per l’if) e poi cosa fare (do) e cosa accade quando il da farsi è stato fatto (done).
L’esempio è un ciclo che verrà eseguito fintanto che i file prova esisterà.
Notate che per evitare che lo script scriva continuamente a video il messaggio “In attesa che il file venga cancellato” abbiamo inserito il comando sleep, che mette in attesa il l'esecuzione dello script per un numero di secondi specificato (sleep 5); così l’eco viene ripetuta a distanza di 5 secondi.
Quindi se mandiamo in esecuzione attesa.sh, ogni 5 secondi abbiamo questo messaggio; se cancelliamo il file prova della directory /tmp, l’eco sarà “File prova cancellato”.
Veniamo adesso al ciclo for, utilizzabile quando è necessario iterare una lista di valori e quindi  ripetere per un numero finito di volte lo stesso blocco di istruzioni; bash permette di farlo in due modalità, ossia due modi alternativi di vedere la stessa.
Tradizionalmente nei linguaggi di programmazione il ciclo for itera su indici numerici, mentre in bash è molto più potente, perché consente di iterare su valori.
Ecco un esempio di ciclo for in bash.
nomi=’Marco Giulio Andrea’
for nome in $nomi
do
   echo $nome
done
L'esempio permette di effettuare la eco dei vari nomi presenti nella variabile nomi; la sintassi è molto semplice e for nome della variabile di iterazione in seguito dal dalla lista di valori su cui iterare. In questo caso stiamo utilizzando la variabile nomi definita prima; quello che farà bash sarà espandere questa stringa fatta da tre nomi in una lista di tre valori e il ciclo for eseguirà l'istruzione echo iterando su questi tre valori, ossia proponendo una eco per ogni nome in lista, dal primo all’ultimo.
Un'altra possibilità è utilizzare la sintassi delle parentesi graffe, come vedete nell’esempio che segue, per generare una lista invece di intervalli numerici di valori numerici quindi:
for indice in {1..5}
do
   echo $indice
done
I valori tra parentesi graffa 1.. 5 sono interpretati da bash come l'intervallo di 1÷5 e quindi 1, 2, 3, 4, 5; le relative eco verranno a succedersi tante volte quanti sono i valori nell’intervallo.
Gli esempi fatti possono essere utilizzati come base per sviluppare elaborazioni più complesse.
Funzioni di bash
In bash, una funzione è un blocco di comandi al quale è assegnato un nome; le funzioni consentono di modularizzare lo script, quando si ritiene necessario richiamare lo stesso blocco di istruzioni tante volte, piuttosto che ripeterle all’interno dello script stesso. Nell’esempio che segue abbiamo definito la funzione “saluta” che contiene un'unica istruzione: la eco Ciao.
#!/bin/bash
Saluta/b {
     echo “Ciao”
}
Saluta
Nell'esecuzione dello script la richiamiamo semplicemente con il suo nome e bash effettuerà la chiamata, per così dire, alla funzione saluta, eseguendo tutte le istruzioni e tutti i comandi che la compongono.
Una piccola variante è la funzione proposta qui di seguito: 
#!/bin/bash
Saluta/b {
     echo “Ciao $1”
}
Saluta “pippo”
che mostra come attribuire degli argomenti, quindi dei parametri, alle funzioni presenti negli script bash; la sintassi è la stessa utilizzata per gli argomenti dello script stesso, quindi se all'interno della funzione saluta utilizziamo la variabile $1 utilizzeremo il primo argomento specificato dopo la chiamata della funzione saluta. Quindi, come vedete, l'istruzione che richiama la funzione passa un argomento, mentre la funzione saluta utilizza la variabile $1 per scrivere la stringa Ciao.
Quindi se lanciamo questo script otterremo una eco del tipo: Ciao Pippo.
Notate che se $1 non è definita e invochiamo la funzione saluta senza specificare un argomento, siccome $1 è vuota non viene istanziata in alcun modo e viene trattata come se fosse una stringa vuota, quindi in output abbiamo ciao seguito da nulla.
Le funzioni definite all'interno di uno script sono visibili solo all'interno dello script stesso; è possibile richiamare funzioni all'interno di altre funzioni ma bisogna ricordarsi dell'ordine di definizione, quindi una funzione definita prima di un'altra può essere chiamata all'interno di quella definita dopo, ma non è detto che tutte le versioni di bash supportino il contrario.
Inline scripting
Passiamo ai comandi dello script nella riga di comando, per i quali vale la regola che sono separati da punto e virgola invece che da nuova linea; il simbolo ; in bash non è obbligatorio, ma è utilizzato per separare i comandi che si trovano sulla stessa riga.
L’utilizzo di comandi sulla stessa riga separati da ; è ciò che permette il cosiddetto “inline scripting”, che torna utile quando è necessario utilizzare solo un ciclo for, allorché non è conveniente scrivere uno script e assegnare privilegi d'esecuzione solo per esso.
Quindi la sintassi inline permette di effettuare un for su un elenco di valori direttamente dalla riga di comando, come in questo esempio:
for valore in {1..5}; do echo $valore; done 
dove bash eseguirà il ciclo for esattamente come avrebbe fatto se fosse stato all'interno di uno script.
Come già visto, la sintassi del for normalmente richiederebbe la definizione di più linee, quindi  dopo l'intervallo di valori dovremmo andare a capo; questo può essere effettuato utilizzando il comando backslash così come, nella sintassi inline, con punto e virgola.
Ora riprendiamo l’esempio proposto nella spiegazione del controllo di flusso:
if [ -e “/tmp/prova” ]
then
echo “Il file prova esiste”
else
echo “Il file prova non esiste”
fi
e trasformiamolo in questo:
if [ -e $1 ]
then
echo “Il file $1 esiste”
else
echo “Il file $1 non esiste”
fi
Lo scopo è verificare l’esistenza della variabile $1.
Se salviamo il file e poi lo eseguiamo passando come parametro il nome di un file esistente in un percorso specificato, ma non è $1, lo schermo risponde che il file esiste, tuttavia lo script non esegue alcun controllo sul numero di parametri che sono stati passati o sulla validità del file stesso.
Se invochiamo il file senza alcun nome file e la variabile $1 è vuota, la condizione di esistenza sul file vuoto è vera e quindi lo script restituisce il messaggio “Il file esiste”. Insomma, possono verificarsi situazioni paradossali.
Questo ci ricorda che nella programmazione il controllo dell'input è a carico del programmatore, quindi dobbiamo essere noi a verificare che tutte le possibili condizioni siano gestite correttamente dal programma e lo stesso accade nel caso in cui vogliamo verificare se certi parametri esistono o meno. Nel caso di $1 potrebbo testare il valore della variabile che ci dice quanti sono gli argomenti passati alla funzione e verificare se è stato passato almeno un argomento.
 

Quando si dice Linux si intende qualcosa di più di un sistema operativo e non tanto per il livello qualitativo e la versatilità e potenza che offre rispetto a “concorrenti” come Microsoft Windows, quanto perché Linux non è un sistema operativo ma una famiglia...un’intera classe. Esistono, infatti, molti sistemi operativi che si fregiano di tale nome e che non a caso definiamo Linux-like.
Linux è un sistema operativo derivato dal potentissimo Unix, che deve i natali a un’idea di Linus Torvald e che con Unix condivide la struttura e l’impostazione del kernel. Tutti i Linux sono quindi sistemi operativi con un kernel strutturalmente simile e, siccome a differenza di Unix e di suoi “simili” come Solaris ecc., è open-source, le varie versioni esistenti sono sviluppate e personalizzate a partire dal kernel, proprio perché esso è di pubblico dominio e viene rilasciato sotto licenza GNU. Workstation
Le versioni di Linux sono chiamate distribuzioni proprio perché generate e distribuite a partire da un kernel comune, da Linux User Group o sviluppatori o, ancora, aziende; troviamo quindi una gran quantità di distribuzioni che si distinguono sia per prestazioni e funzionalità disponibili, sia per supporto e disponibilità di aggiornamenti costanti e frequenti.
Tra le varie distribuzioni, Slackware, Ubuntu, Red Hat, Debian (probabilmente la più prestante), Mint, Fedora ed altre ancora.
Linux: che cos’è?
Linux è un sistema operativo di libero utilizzo e distribuito e fruibile con licenza open source.
Un sistema operativo è un insieme di programmi che gestisce le risorse hardware e software di un sistema di elaborazione (quindi di un computer, sia esso Personal, Micro, Mini ecc.) fornendo servizi comuni ai programmi applicativi. La sua attività è illustrata nell’immagine seguente, dove distinguiamo i livelli utente (User), applicazione (Application), sistema operativo (Operating System) e fisico (Hardware).
 Immagine
L’'immagine mostra un’architettura a layer in cui i livelli più bassi sono rappresentati dall'hardware (dalle risorse fisiche del sistema) e poi abbiamo il sistema operativo, che è lo strato blu che fa da tramite tra le applicazioni e le risorse di calcolo (le risorse hardware) quindi sistema operativo è proprio tutto quell'insieme di software che nasce con lo scopo di essere a servizio delle applicazioni.
Facciamo un esempio utile a capirci: uno dei servizi comunemente offerti da un sistema operativo è la gestione del file system; l'architettura delle directory e il modo con cui le informazioni vengono memorizzate in un sistema informativo è un qualcosa di codificato all'interno di una parte del sistema operativo è impensabile credere che ogni volta che si deve sviluppare un'applicazione sia questa a dover implementare tutte le funzionalità necessarie a gestire la memorizzazione di un certo insieme di informazioni a partire dalla gestione dei cluster dell'hard disk, dei settori e quant'altro. Quindi queste problematiche vengono risolte a livello di sistema.
Linux è un sistema operativo particolare, perché libero e open source: questo significa che su Internet è disponibile a chiunque il codice sorgente del sistema operativo; andando sul sito www.kernel.org potete collegarvi al sito degli sviluppatori dove sono disponibili i sorgenti del kernel stesso.
Linux è un sistema operativo libero perché è offerto non da una un'azienda (perché non è un prodotto commerciale) ma da una fondazione che ne cura lo sviluppo e lo fornisce gratuitamente a chiunque lo voglia utilizzare per implementare le proprie soluzioni informative.
Unix: il padre di Linux
Come accennato, Linux deriva da Unix, che è un sistema operativo sviluppato originariamente dai Bell Labs. Possiamo definire cronologicamente lo sviluppo di Unix con queste tappe:

  • intorno al 1960 vengono compiuti i primi lavori sul mainframe GE-645 (Multics);

  • 1971: Linux viene annunciato internamente ai Bell Labs;

  • 1973: Linux viene annunciato al pubblico;

  • 1975: avviene il Rilascio di “Research Unix”;

  • 1977: viene rilasciata la prima versione di BSD;

  • 1982: avviene il rilascio di HP-UX;

  • 1983: rilascio di SunOS 1.0;

  • 1988: IEEE rilascia le specifiche del primo standard POSIX;

  • 1989: avviene il rilascio di NextSTEP 1.0.


Ma la vera rivoluzione avviene quando prende il via il progetto GNU, ossia nel 1983, quando viene implementata la prima versione libera di Unix.
Unix è un sistema operativo sviluppato per conto di General Electric prima e di TNT in seguito, in America negli anni ’60 del secolo scorso, quando l'informatica era relegata al mondo dei mainframe e ancora non esisteva il Personal Computer. I primi lavori su Unix iniziarono nel 1960 su un mainframe della General electrics GS645 sul quale prima girava un altro sistema operativo: multix (il nome io unix deriva proprio in contrapposizione con quel sistema); Unix si deve all’opera di tre sviluppatori, D. Ritchie, K. Thompson e B. Kernighan, di cui vedete le foto di seguito.
Immagine
Prima di poter sviluppare il sistema operativo passarono 9 anni e solo nel 1973 Unix venne rilasciato pubblicamente nel mondo mainframe come prodotto commerciale e nel 1975 due anni fu rilasciata una versione con una licenza particolare che consentiva alle agli istituti di formazione e alle università di poterlo modificare.
Nel 1977 nasce un altro sistema operativo ispirato alla filosofia Unix, ossia il sistema BSD della Berkeley software Distribution.
Altro momento importante fu il rilascio, nel 1989, di NextSTEP 1.0, ad opera della Next Step, compagnia fondata da Steve Jobs, che divenne la base del sistema operativo MacOSx.
Unix non è soltanto un sistema operativo, ma una specifica e una filosofia: un insieme di idee estremamente rivoluzionarie per il tempo, che hanno ispirato un la progettazione di tutti i sistemi operativi moderni, anche quelli non direttamente riconducibili ai Unix, come ad esempio Windows NT.
Unix ha le seguenti caratteristiche:

  • portabile;

  • multi-utente;

  • multi-tasking;

  • file system gerarchico;

  • Inter Process Communication;

  • modularità: la unix philosophy. 


Portabilità
Analizziamo una ad una le caratteristiche di Unix, partendo dal concetto di portabilità.
Fino a quel momento il software veniva sviluppato il linguaggio macchina (quello che oggi chiamiamo Assembly) cioè in un linguaggio fortemente legato al particolare hardware sul quale il programma doveva girare; questo limitava fortemente la portabilità del codice, nel senso che far girare lo stesso programma su una macchina diversa comportava una riscrittura e la riscrittura poteva essere un'operazione molto complessa, proprio perché scrivendo in un linguaggio così di basso livello come quello costituito dalle istruzioni direttamente comprensibile dalla CPU è chiaro che passando da un'architettura un'altra da un hardware e un altro potevano esserci notevoli problemi: ad esempio cosa succede se è un’istruzione richiesta dal software originale non è disponibile nel seto del processore della macchina su cui bisogna portare il codice?
La necessità di risolvere il problema ispirò tre ricercatori dei Bell Labs, dove venne sviluppato prima di tutto un nuovo linguaggio di programmazione di alto livello derivato da un precedente progetto sviluppato in seno ai Bell Labs, da cui nacque il C, ossia un linguaggio di programmazione tutt'ora utilizzato.
Poi i tre ricercatori si dotarono di uno strumento di più alto livello con il quale poter sviluppare poi il sistema operativo Unix, che quindi fu il primo sistema operativo essere scritto in linguaggio C.
Ciò ne garantisce una certa portabilità, tanto che inizialmente il progetto venne scritto per un mainframe della General electrics e poi in seguito fu portato su altre macchine, sui PDP (per esempio sul pdp-7 e sul PDP 11).
Multi-utenza
Un altro principio importante e rivoluzionario di Unix fu la multi-utenza: più utenti possono, su una stessa macchina, far girare programmi diversi o comunque possono voler conservare ognuno i propri dati senza che gli altri possano in qualche modo modificarli o accedervi; un sistema operativo multiutente viene progettato proprio per supportare queste esigenze, ossia per riconoscere i differenti utenti ed assegnare a ciascuno un ambiente dove far girare i propri programmi e memorizzare i propri dati in totale autonomia.
Multi-tasking
Un'altra caratteristica importante, che oggi diamo per scontato ma che non era assolutamente scontata all'epoca, è il multi-tasking, ossia la capacità di far girare più programmi contemporaneamente; anche in ambito mainframe, negli anni ‘60 questo non era per nulla scontato, sia per le limitate risorse hardware, sia perché implementare politiche di multitasking vere e proprie scrivendo un sistema operativo esclusivamente linguaggio macchina è un'impresa non da poco.
Gli sviluppatori di Unix ci riuscirono.
File system gerarchico
Altro concetto rivoluzionario introdotto da Unix è un file system gerarchico: fino a quel momento la memorizzazione dei dati era appannaggio dell'applicazione del programma o, se vogliamo, dell’unico programma che il calcolatore seguiva e questo comportava una eterogeneità nel modo di gestire le informazioni che poteva essere sicuramente problematica.
Offrire alle applicazioni un'interfaccia comune per poter memorizzare le informazioni è lo stesso principio che oggi utilizziamo sui nostri calcolatori, quindi una struttura gerarchica fatta di cartelle (directory) e di file di vario tipo, si deve alla specifica di Unix.
Inter Process Communication e modularità
Altri due importantissimi aspetti riguardano la Inter Process Communication e la modularità: la prima è fondamentale perché Unix è un sistema operativo multiprogrammato multi-tasking, quindi è importante che i vari programmi girino contemporaneamente o più o meno  contemporaneamente. Ci sono varie possibilità per implementare il multi-tasking a livello fisico: se le unità di elaborazione sono tante è possibile effettivamente eseguire più programmi contemporaneamente, ma se abbiamo un’unica CPU, in realtà il multi-tasking viene simulato eseguendo le istruzioni dei vari programmi in modo sequenziale. Si tratta quindi di multi-tasking in Time Sharing, cioè a divisione di tempo.
Allora è importante che i vari programmi non siano un qualcosa di isolato, ma possano comunicare tra di loro: questo aspetto è importante perché rientra in quella che poi verrà definita proprio Unix Philosophy, ossia la filosofia di Unix, che consiste nello sviluppare sistemi informativi cercando di massimizzare la modularità e non fare dei programmi monolitici che sono in grado di risolvere un solo problema ma cercare di suddividere il problema è in tanti programmi diversi che possono quindi essere riutilizzati per realizzare, collaborando, servizi differenti.
La Inter Process Communication consente di implementare dei sistemi informativi in cui i processi siano effettivamente modulari; per comprenderla facciamo un esempio: sappiamo che per sviluppare un'applicazione web che abbia la necessità di memorizzare delle informazioni su un database è necessario avere un server web, un interprete di un certo linguaggio di scripting PHP o un ambiente di esecuzione di un'applicazione web come Tomcat, oltre a un database. Queste tre entità comunicano tra loro scambiandosi dati al fine di implementare un servizio comune: in questo caso, l'applicazione web.
Questi tre servizi sono di fatto dei processi che girano sul nostro server in multitasking, contemporaneamente, e comunicano tra di loro attraverso dei meccanismi di comunicazione interprocesso, che è poi là Inter Process Communication.
Essa può essere implementata ad esempio con le pipe, gli Unix socket ecc.
IL PROGETTO GNU E LA FSF
Un altro momento fondamentale della storia di Linux è il progetto Blue: nel 1983 Richard Stallman decide di intraprendere una “crociata” contro le implementazioni proprietarie e contro il software chiuso; quindi di fatto inizia una battaglia che ha delle implicazioni delle ramificazioni del mondo moderno notevoli, con l'obiettivo di rendere il software aperto e libero.
Allora, nel 1983 nasce inizia il progetto Blue con l'obiettivo di riscrivere un sistema operativo Unix-like completamente open source, completamente aperto e di fatto il progetto ottiene un notevole successo perché si scrisse un compilatore C da zero (il famoso GCC) e tutta una serie di librerie a supporto della compilazione linguaggio C.
Nel 1983, dunque, nasce GNU, implementazione aperta e libera di Unix, che consentirà agli sviluppatori di tutto il mondo di mettere mano al codice di Unix sviluppando kernel personalizzati e adattabili ad hardware più “semplici” di quelli per cui Unix nasceva.
GNU è un sistema operativo distribuito come software di libero utilizzo; di norma il software libero è rilasciato con una licenza di utilizzo che normalmente è la GNU General Public License (GNU GPL). La documentazione per il software libero deve essere documentazione libera, in modo che si possa distribuire e migliorare assieme al software che essa descrive.
La licenza spiega agli utenti come possono utilizzare un prodotto e, nel caso specifico, un software ai fini didattici, sperimentali, commerciali, affinché possa essere incorporato e integrato in qualcosa di più complesso.
Lo sviluppo di GNU ha reso possibile utilizzare un computer senza fare affidamento su software proprietario.
Quando si parla di Linux, essendo, esso, nato da GNU, è opportuno chiamarlo GNU/Linux.
GNU ("GNU's Not Unix") è un sistema operativo Unix-like ideato nel 1984 da Richard Stallman e promosso dalla Free Software Foundation (fondata dallo stesso Stallman nel 1985) anche detta FSF, allo scopo di ottenere un sistema operativo completo utilizzando esclusivamente software libero.
Allo stesso Richard Stallman si deve la clausola Copyleft; la GPL, che è una delle licenze più utilizzate nella storia del free software, in realtà include una clausola Copyleft che costringe sostanzialmente chi adotta un lavoro concesso in licenza GPL ad adottare lo stesso (o compatibile) tipo di licenza nelle opere derivate. Per quanto il proposito di Stallman fosse buono, tale vincolo ha spinto la comunità di sviluppatori a cercare licenze meno vincolanti e sono apparse e sono state consolidate licenze più permissive come la licenza Apache Software o BSD. Da tempo, licenze permissive (che non includono clausole copyleft) hanno guadagnato una significativa attrattiva nella comunità del software.
A parte questa considerazione, torniamo a GNU, i cui componenti sono:

  • compilatore C (GCC);

  • la GNU C library (glibc);

  • coreutils;

  • binutils;

  • la shell Bash;

  • Kernel? GNU Hurd… / Linux.


Dato che GNU Hurd, il kernel ufficiale del progetto, non è considerato pronto per la distribuzione, GNU viene in genere utilizzato congiuntamente ad altri kernel tra cui Linux, Linux-libre, XNU o quello utilizzato da FreeBSD.
La parola GNU si pronuncia /gnu:/ (gh-nù) e non /ɲu:/ per non confonderlo con l'omonima specie animale o con l'aggettivo inglese new.
Minix
Lo sviluppo e il debug di un sistema operativo multiprogrammato e che funzionasse come Unix fu arduo e si arrivò presto a un punto di stallo; il progetto Linux troverà nuova vita quando un informatico finlandese scriverà un kernel Linux basandosi sul compilatore e sulle utility già sviluppate in seno al progetto.
Ma ciò accadde dopo la nascita di Minix, altro momento storico della storia di Linux: era il 1987, quando A. Tanenbaum rilasciò MINIX (Mini Unix, cosiddetto perché a differenza di Unix nasceva per funzionare su PC IBM e compatibili e quindi per architettura i286 e i386) nella sua prima release 1.0. Minix era ed è un sistema operativo didattico, a supporto del corso di sistemi tenuto dallo stesso Tanenbaum. Scritto originariamente solo per PC IBM compatibili, oggi è disponibile per una gran varietà di architetture hardware.
A differenza dell’Unix del progetto Blue, Minix non è un sistema operativo sviluppato con lo scopo di girare effettivamente su mainframe o di offrire servizi particolari, ma venne scritto e sviluppato da un docente universitario come sistema operativo didattico come un caso d'uso concreto qualcosa da mostrare a supporto del proprio corso di sistemi operativi.
Nel 2015 Intel ha iniziato a utilizzare MINIX 3 per la IME (Intel Management Engine) delle sue CPU x86, oggetto di qualche polemica perché in termini di sicurezza si sono scoperte delle vulnerabilità sulla e-mail dovute a “ingenuità” nel nello sviluppo; ma non si possono fare colpe allo sviluppatore perché Minix non è mai stato concepito per essere un prodotto commerciale, adottato in quel componente della CPU che purtroppo un componente di bassissimo livello Perché di fatto è un piccolo sistemino a latere che governa le operazioni della CPU e può accedere a praticamente ogni risorsa di calcolo della macchina senza che la vera CPU e il loro sistema operativo ne sappia nulla.
Il kernel Linux
Passaggio epocale nella storia di Linux è la creazione del suo kernel, avvenuta nel 1991 ad opera di Linus Torvalds rilascia un kernel per PC 386 inedito, ed alcune utility GNU (GCC e Bash) ricompilate per questa nuova piattaforma.
La vulnerabilità di Minix è uno dei motivi per cui nasce Linux: infatti l'autore della prima versione del kernel di Linux, Linus Torvalds, è un informatico finlandese che all'epoca (1991) era uno studente di informatica che usava Minix in seno ai suoi studi universitari e un po’ per studio è un po’ per mettersi alla prova, iniziò a sviluppare un kernel differente da Minix, ispirato a Unix e compatibile con il progetto GNU.
Torvalds annunciò di aver creato Linux su una BBS, invitando chiunque a fornire suggerimenti, fornendo il codice sorgente e iniziando a effettuare il porting del codice stesso su varie macchine.
Adattò il compilatore e la shell (interfaccia utente) è per questo nuovo ambiente creando così un sistema operativo minimale ma completo.
Quindi, di fatto Linus Torvalds offre il modulo mancante al progetto GNU e che presto si rivela il progetto di successo rispetto al kernel del progetto GNU e per alcune scelte progettuali Linux è un kernel molto più semplice.
Linux è sistema operativo Unix-like ed è un progetto completamente open source, rilasciato con licenza GPL; essendo la combinazione di GNU e del lavoro di Torvalds, Linux è meglio noto come GNU/Linux.
I sistemi operativi Unix-like sono dei progetti che si ispirano alle linee guida dei primi Unix e sono di fatto delle riscritture, ossia dei software compatibili che si comportano allo stesso modo di Unix ma non sono Unix e quindi non sono basati su quel sul codice sorgente del sistema operativo.
Utilizzo di Linux
Oggi siamo veramente circondati da Linux: magari non lo sappiamo neanche perché molti sistemi embedded sono basati su Linux e quindi diversi dispositivi Internet of Things, la stragrande maggioranza di dispositivi di rete anche di uso domestico come router Access Point, IP Cam e quant'altro, sistemi di infotainment (ad esempio quelli a bordo degli aerei, ossia gli schermi attraverso cui è possibile vedere dei film) spesso sono implementati con dei sistemi embedded che fanno girare una personale versione di Linux.
Ma Linux governa anche sistemi per la domotica, le nostre Smart-TV e ovviamente dispositivi mobile basati su Android che tutti conosciamo e che utilizza Linux come kernel e alcune applicazioni del progetto GNU per funzionare. Ma ci sono poi anche altri progetti come FirefoxOS
e Nokia Maemo.
Linux è utilizzato in ambito desktop anche se non con una grande diffusione, ma sappiamo che esistono diverse distribuzioni per Personal Computer, Server e anche mainframe. Per quanto riguarda l'ambito di high performance computing, praticamente la maggioranza ha quasi totalità dei supercomputer oggi presenti sul pianeta fanno girare una qualche versione di Linux.
Distribuzioni Linux
Una piccola nota su come viene distribuito il software disponibile per questa piattaforma: siccome Linux è un progetto aperto che chiunque può personalizzare e ridistribuire, in ambiente Linux si usa parlare di “distribuzioni” cioè di collezioni di software che permettono di installare il sistema operativo basato su Linux corredato da una serie di applicazioni compilate per quell’ambiente, che permettono di svolgere un test specifico.
Quindi, proprio per la natura del progetto che è aperta e che invita chiunque a personalizzare, modificare, esistono tantissime distribuzioni e ad oggi se ne contano più di 800.
Ci sono distribuzioni che si differenziano perché la loro utenza di riferimento e un’utenza  commerciale che magari ha bisogno di supporto anche a pagamento e ci sono distribuzioni che sono disponibili solo per alcune piattaforme o per alcune architetture o distribuzione che sono certificate per girare su una certa architettura e quindi in quel caso sceglieremo una distribuzione che va bene per la nostra piattaforma.
Poi le distribuzioni si differenziano per le funzionalità: oltre a distribuzioni generali che vanno bene per implementare qualunque tipo di servizio, ci sono distribuzioni altamente specializzate: per esempio ci sono distribuzioni che consentono di implementare un firewall di sistema e fanno solo quello, firewall di rete o distribuzioni che consentono di riutilizzare un vecchio PC come NAS, per esempio, quindi sono altamente specializzate. Altre, invece, possono essere utilizzate per scopi più generici, perché dispongono di una collezione di software più ampia.
Altro aspetto da considerare nella scelta della distribuzione Linux da adottare sono le politiche di gestione del progetto: se c'è dietro una community di appassionati, piuttosto, che è un'azienda che ha interesse a promuovere un prodotto con delle scadenze precise e delle linee guida per il supporto.
Quando parliamo di Linux non parliamo di un sistema operativo ma di una famiglia di sistemi operativi, per cui poi la scelta del sistema da utilizzare, in particolare passa attraverso l'individuazione della distribuzione più adatta ai nostri scopi.
Possiamo così riassumere il market share di Linux:

  • desktop: 8,5%;

  • web server: da 60 a 90%;

  • Mobile: > 80%

  • Supercomputer: 100% dei top 500.


Oggi i dati sui web server sono discordanti perché ci sono talmente tanti siti web, che è veramente difficile mantenere delle statistiche aggiornate.
A livello di Personal Computer desktop la diffusione è bassa perché per politiche commerciali piuttosto aggressive, parte dei PC che si possono acquistare esce con un sistema operativo, quindi molti utenti non sanno neanche che ne esistono altri... che esiste Linux.
Inoltre Linux viene ancora percepito come un sistema operativo più da addetto da addetti ai lavori.
Sicurezza di Linux
Però è diffusa l’opinione che sia un sistema operativo sicuro. In realtà, come affermava G. Spafford “L’unico sistema realmente sicuro è un sistema spento”  perché data la complessità del software e dell'hardware odierni è sempre possibile, quantomeno probabile, che si possano individuare azioni che l'utente può effettuare o che i programmi possono effettuare autonomamente, capaci di portare direttamente o indirettamente a compromettere la sicurezza del sistema; e la storia ci insegna che sia in ambito di Personal Computer che di grandi mainframe, a volte si tratta di problemi di sicurezza legati a delle ingenuità da parte degli sviluppatori ed altre si tratta veramente di problemi di sicurezza che si evidenziano dopo aver effettuato delle analisi e degli studi molto approfonditi sulla faccenda.
Un esempio è il recente caso delle vulnerabilità di diverse architetture, in primo luogo delle x86  Intel, ma poi si è visto che anche altre CPU sono affette da problemi analoghi che sono stati battezzati Spectre e Meltdown.
Parliamo di CPU perché uno degli aspetti da considerare è che la sicurezza di un sistema informatico non è soltanto data dal sistema operativo, ma da tutte le sue componenti, quindi il sistema operativo può essere il più sicuro del mondo ma se l'hardware di per sè ha delle vulnerabilità, queste potranno essere sfruttate. L'esempio lampante è proprio quello di spectre e meltdown: si tratta di due vulnerabilità di sicurezza individuate inizialmente sull’architettura x86, ma poi si è visto che delle varianti di questi sistemi di attacco si possono implementare anche per altre architetture (anche sulla diffusissima ARM). Tali attacchi sono modi di ottenere delle informazioni che non dovrebbero essere accessibili e si tratta di modalità di interazione con la CPU che invece permettono a un malintenzionato di ottenere indirettamente queste informazioni.
Le vulnerabilità riguardano una particolare modalità di esecuzione dei programmi all'interno della CPU che oggi è di uso comune perché è un espediente che consente di massimizzare le prestazioni dei nostri sistemi informatici: si tratta della esecuzione fuori ordine e in particolare dell'esecuzione speculativa: questi due termini significano in pratica che i programmi che facciamo girare sulle nostre macchine non vengono eseguiti in modo sequenziale, cioè istruzione per istruzione come sono stati scritti, perché le CPU moderne sono dotate di unità molto complesse che eseguono le istruzioni non appena le unità in grado di eseguirle sono disponibili, invece che seguendo il flusso logico del programma. L'unità di esecuzione speculativa fa proprio questo: dato un programma in ingresso, decide in modo probabilistico se eseguire un'istruzione piuttosto che un'altra e poi ricompone i risultati alla fine.
Quindi per qualsiasi sistema operativo e neppure per Linux possiamo dire che sia sicuro in senso assoluto, perché dipende dall'hardware sottostante.
Esistono virus per Linux?
Altri due esempi noti negli ultimi tempi sono gli attacchi ShellShock ed HeartBleed: si tratta di vulnerabilità che hanno riguardato invece degli applicativi: nel primo caso la shell e nell'altro il layer TLS, che vengono comunemente utilizzati anche in ambiente Linux ma che non riguardano il sistema operativo Linux di per sè.
La sicurezza del sistema operativo c'entra fino a un certo punto perché ancora una volta è tutto l'ambiente che deve essere sicuro. Quindi se le nostre applicazioni se i programmi che facciamo girare non sono sicuri possono diventare vettore di attacchi.
Ma perché, allora, si parla di Linux? Perché viene percepito come un sistema operativo sicuro? La risposta è nel principio del Security through obscurity, cioè la sicurezza insita nel fatto che non si conoscono i dettagli di un sistema operativo, quindi pensare che è un sistema operativo proprietario sia più sicuro perché nessuno ha a disposizione i codici sorgenti e quindi l'analisi del comportamento dello stesso risulta più complessa, è in realtà un argomento a favore della sicurezza. Infatti si è visto che è un sistema operativo open source invece è in genere più sicuro perché molte più persone possono revisionare il codice sorgente è accorgersi se ci sono degli eventuali problemi di sicurezza e soprattutto possono intervenire in caso di vulnerabilità dichiarate: per esempio in ambiente Linux le prime patch o i primi workaround per rendere sicure le macchine affette da spectre e meltdown sono state rilasciate in ambiente Linux.
Poi esistono dei progetti nati apposta per rendere il sistema operativo sicuro e uno di questi è il progetto SELinux, che è un modulo contenente una serie di estensioni nate per il sistema operativo che governano il modo con cui esso offre servizi alle applicazioni e agli utenti; in particolare si tratta di un modulo che funziona per regole e dà al sistema operativo la possibilità di offrire un determinato servizio a un'applicazione o a un utente a meno che l'amministratore di sistema non abbia esplicitamente indicato delle regole che lo consentano.
Cio è ampiamente diffuso in ambito Linux perché effettivamente permette di avere maggiore controllo sulle attività del sistema e sui servizi offerti agli utenti e alle applicazioni.
Compatibilità di Linux
Linux non solo è un sistema operativo estremamente diffuso perché può essere facilmente plasmato e adattato a vari hardware (da uno smartphone a un mainframe), ma è anche un sistema che a una certa interoperabilità con altri ambienti. Intanto ricordiamo che un sistema che si compila e ciò significa che si integra bene in ambienti dove sono presenti altri Unix.
Questo vale non soltanto per l’interoperabilità tra macchine, ma soprattutto per l’interoperabilità tra persone: un sistemista abituato a gestire un sistema Unix non avrà grosse difficoltà a gestire un sistema Linux e inoltre esistono diversi progetti nati proprio per garantire la maggiore interoperabilità tra sistemi Linux. Ad esempio Samba è un progetto molto noto che permette a un server Linux di integrarsi in una rete Windows; addirittura è possibile utilizzare un server Linux con Samba per implementare un Domain controller Windows, quindi poter gestire una rete Windows senza avere Windows Server, ma utilizzando Linux al suo posto.
Poi esistono dei layer di compatibilità che permettono ad esempio in ambiente PC di far girare applicazioni nate per windows su Linux: è questo il progetto Wine e da qualche tempo c'è la possibilità di fare anche il contrario, grazie al WSL, che un layer di compatibilità sviluppato da Microsoft, grazie al quale è possibile far girare binari eseguibili per Linux in ambiente Windows.
Questi due progetti sono molto interessanti perché non si tratta di virtualizzazione (niente macchina virtuale...) ma di emulazione di sistema; si tratta di un layer che permette di prendere un file binario eseguibile per una certa piattaforma così com'è e farlo girare in un altro ambiente. Ovviamente questi eseguibili devono essere compilati per quella particolare architettura, cioè non si può pensare di prendere un eseguibile per Windows e farlo girare su una macchina Power PC. Però Wine e WSL permettono di nascondere all'applicazione il fatto che non si trova nel suo ambiente nativo, ma opera in un ambiente completamente diverso e questo effettivamente permette di avere maggiore interoperabilità, cioè consente di integrare un client Linux, per esempio all'interno di una realtà in cui non si utilizza un'applicazione che è scritta per un altro sistema operativo.

via/coretech

Rispondi