INTRODUZIONE AL SISTEMA OPERATIVO LINUX



Documenti analoghi
Il Software. Il software del PC. Il BIOS

Il Sistema Operativo (1)

FoLUG Forlì Linux User Group. Partizionamento

Definizione Parte del software che gestisce I programmi applicativi L interfaccia tra il calcolatore e i programmi applicativi Le funzionalità di base

MANUALE EDICOLA 04.05

NOZIONI BASE SHELL E SCRIPT LINUX

Corso di Informatica

Il SOFTWARE DI BASE (o SOFTWARE DI SISTEMA)

Il Software e Il Sistema Operativo. Prof. Francesco Accarino IIS Altiero Spinelli A.S. 09/10

Dispensa di Informatica I.1

Approccio stratificato

Parte V. Sistemi Operativi & Reti. Sistemi Operativi. Sistemi Operativi

Software di sistema e software applicativo. I programmi che fanno funzionare il computer e quelli che gli permettono di svolgere attività specifiche

Introduzione alle tecnologie informatiche. Strumenti mentali per il futuro

Software relazione. Software di base Software applicativo. Hardware. Bios. Sistema operativo. Programmi applicativi

NOZIONI BASE PER ESERCITAZIONI

Software di base. Corso di Fondamenti di Informatica

Il software del PC. Il BIOS

PARTE 4 La Macchina Software

Il Sistema Operativo Linux

Il web server Apache Lezione n. 3. Introduzione

Organizzazione di Sistemi Operativi e Reti

Sistemi Operativi STRUTTURA DEI SISTEMI OPERATIVI 3.1. Sistemi Operativi. D. Talia - UNICAL

Terza lezione: Directory e File system di Linux

Il computer: primi elementi

Installazione LINUX 10.0

Il software impiegato su un computer si distingue in: Sistema Operativo Compilatori per produrre programmi

Informatica 1 Lezione 1

Sistemi Operativi IMPLEMENTAZIONE DEL FILE SYSTEM. D. Talia - UNICAL. Sistemi Operativi 9.1

Architetture Applicative

Procedura di installazione di Xubuntu 8.10 su un PC

Sistemi Operativi IMPLEMENTAZIONE DEL FILE SYSTEM. Implementazione del File System. Struttura del File System. Implementazione

Sistemi operativi. Esempi di sistemi operativi

Il sistema operativo UNIX/Linux. Gli script di shell

Excel. A cura di Luigi Labonia. luigi.lab@libero.it

HARDWARE. Relazione di Informatica

MODELLO CLIENT/SERVER. Gianluca Daino Dipartimento di Ingegneria dell Informazione Università degli Studi di Siena

Informatica - A.A. 2010/11

Benvenuti/e.

Sistema Operativo di un Router (IOS Software)

Corso ForTIC C2 LEZIONE n. 8. Cos'è la shell Le variabili d'ambiente L'uso della shell per la realizzazione di semplici script

SOMMARIO... 3 INTRODUZIONE...

. A primi passi con microsoft a.ccepss SommarIo: i S 1. aprire e chiudere microsoft access Start (o avvio) l i b tutti i pro- grammi

Il sistema operativo: interazione con l utente

Sistemi Operativi. Interfaccia del File System FILE SYSTEM : INTERFACCIA. Concetto di File. Metodi di Accesso. Struttura delle Directory

CTVClient. Dopo aver inserito correttamente i dati, verrà visualizzata la schermata del tabellone con i giorni e le ore.

GHPPEditor è un software realizzato per produrre in modo rapido e guidato un part program per controlli numerici Heidenhain.

Modulo. Programmiamo in Pascal. Unità didattiche COSA IMPAREREMO...

IL SISTEMA OPERATIVO IL SISTEMA OPERATIVO INTERFACCE TESTUALI INTERFACCE TESTUALI FUNZIONI DEL SISTEMA OPERATIVO INTERFACCE GRAFICHE

Biblioteca di Cervia NOZIONI BASE DI INFORMATICA

Riferimento rapido per l'installazione SUSE Linux Enterprise Server 11

SISTEMI DI ELABORAZIONE DELLE INFORMAZIONI

Intel One Boot Flash Update Utility Guida dell utente

Mon Ami 3000 Varianti articolo Gestione di varianti articoli

SOFTWARE. È l insieme delle istruzioni che è necessario fornire alla macchina per il suo funzionamento. Vi sono due categorie di software:

Procedure di ripristino del sistema.

Introduzione al sistema operativo Il file system: file, directory,...

STAMPA DI UNA PAGINA SEMPLICE

Definire all'interno del codice un vettore di interi di dimensione DIM, es. int array[] = {1, 5, 2, 4, 8, 1, 1, 9, 11, 4, 12};

1) GESTIONE DELLE POSTAZIONI REMOTE

L informatica INTRODUZIONE. L informatica. Tassonomia: criteri. È la disciplina scientifica che studia

Configurazione della ricerca desktop di Nepomuk. Sebastian Trüg Anne-Marie Mahfouf Traduzione della documentazione in italiano: Federico Zenith

GESGOLF SMS ONLINE. Manuale per l utente

Il File System di Linux

Le Infrastrutture Software ed il Sistema Operativo

Guida alla registrazione on-line di un DataLogger

Riferimento rapido per l'installazione SUSE Linux Enterprise Server 11 SP1

Laboratorio di Informatica

In un modello a strati il SO si pone come un guscio (shell) tra la macchina reale (HW) e le applicazioni 1 :

MANUALE UTENTE Fiscali Free

lo PERSONALIZZARE LA FINESTRA DI WORD 2000

Product Shipping Cost Guida d'installazione ed Utilizzo

PROGRAMMAZIONE DISCIPLINARE INDIVIDUALE

Cosa è un foglio elettronico

All interno del computer si possono individuare 5 componenti principali: SCHEDA MADRE. MICROPROCESSORE che contiene la CPU MEMORIA RAM MEMORIA ROM

Automatizzare i compiti ripetitivi. I file batch. File batch (1) File batch (2) Visualizzazione (2) Visualizzazione

Mac Application Manager 1.3 (SOLO PER TIGER)

Risolvere i problemi di avvio di Windows XP

1. RETI INFORMATICHE CORSO DI LAUREA IN INGEGNERIA INFORMATICA SPECIFICHE DI PROGETTO A.A. 2013/ Lato client

La Filosofia ''Open Source'' ed il Sistema Operativo ''Linux''. Gabriele Turco e Tudor Trani.

Organizzazione della memoria

Il sistema di I/O. Hardware di I/O Interfacce di I/O Software di I/O. Introduzione

Sharpdesk V3.3. Guida all installazione Versione

Procedure di ripristino del sistema.

Linguaggi e Paradigmi di Programmazione

Corso di Alfabetizzazione Informatica

BMSO1001. Virtual Configurator. Istruzioni d uso 02/10-01 PC

Stream EDitor (sed) sed NON modifica l'input 2. L'output viene inviato allo standard output e puo' essere rediretto

Architettura di un sistema operativo

1 -Introduzione MODULO L1

File, Modifica, Visualizza, Strumenti, Messaggio

Introduzione alla. Alessandra Giordani Lunedì 27 febbraio

Istruzioni per l installazione del software per gli esami ICoNExam (Aggiornate al 15/01/2014)

Introduzione alla programmazione in C

Corso di PHP. Prerequisiti. 1 - Introduzione

MODULO 02. Iniziamo a usare il computer

IL MULTIBOOT. Un sistema multiboot consiste nella possibilità di caricare più sistemi operativi sullo stesso computer.

Il database management system Access

Il Sistema Operativo. C. Marrocco. Università degli Studi di Cassino

Le Interfacce Grafiche

Transcript:

VERSIONE 0.18 DI FUSCO FRANCESCO INTRODUZIONE AL SISTEMA OPERATIVO LINUX 1

Se ascolto dimentico, se vedo ricordo, se faccio capisco 1 1 Confucio 2

Indice Capitolo 1: Introduzione a Linux Obiettivi Che cos'è Linux? Installare Linux Capitolo 2: I processi I processi Comandi per controllare il vostro sistema kill Terminare i processi Processi di background Capitolo 3: Avvio di Linux Lavorare con Linux Lavorare come altro utente Distribuzioni I runlevel Avviare i processi nei runlevel Il processo init Controllare init Arrestare init Capitolo 4 Creare le vostre routine in Linux Il file system di Linux Ogni cosa è un file in Linux Capitolo 5 Giorno per giorno con Linux Terminali virtuali Editor di testo in Linux Capitolo 6 Shell in Linux Comandi della shell frequentemente usati Capitolo 7 Pipe Capitolo 8 Ottenere più informazioni con Linux Capitolo 9 Il comando grep Altri comandi più interessanti Capitolo 10 Potenti comandi utente tee > 2> whoami whereis which 3

echo wc Capitolo 11 Comandi vari Capitolo 12 Diventare superutente Capitolo 13: Il filesystem in Linux Il filesystem in Linux Montare i file system Opzioni di montaggio del filesystem Il comando umount - smontare i file system Partizionamento Gerarchia delle directory Le directory I tipi di filesystem Creare un filesystem Buffering del filesystem /etc/fstab Capacità dei filesystem Controllare e riparare i filesystem Filesystem speciali Operazioni sul filesystem Creazione di una directory Il comando mkdir Rimozione di una directory Il comando rmdir Copia di file e directory Il comando cp Rimozione di file e directory Il comando mv Spostare file o directory Elencare i file in una directory I caratteri jolly La struttura base delle directory in Linux Capitolo 14 chmod Permesso sui file in Linux usare chown Capitolo 15 Backup dei vostri file Comprimere i file Decomprimere i file Capitolo 16 Installazione di programmi Aggiornamenti Capitolo 17 Stampare sotto Linux Usare Linux per accedere ad Internet 4

Capitolo 18 Suono in Linux Registrare il suono Formato mp3 Formato ogg Capitolo 19 Interfaccia grafica utente per Linux L'albero della famiglia di GUI Configurazione di X-Windows Browser internet client email Capitolo 20 Amministrazione del sistema Il ruolo di root Delegare l'autorità Aver cura quando si lavora come root Come amministrare gli utenti del sistema Amministrazione degli utenti Altre occupazioni dell'amministratore Modificare i file di configurazione Capitolo 21 Automazione dei task Automazione dei task in Linux Capitolo 22 Strumenti dell'amministratore Editor di testo vi emacs editor di testo alternativi Kate kwrite Elaborazione e manipolazione del testo Capitolo 23 Il kernel di Linux Che cos'è il kernel di Linux Configurazione del kernel Capitolo 24 I servizi del sistema 5

6

Capitolo 1 Introduzione a Linux 7

Che cos'è Unix Il sistema operativo UNIX fu originariamente sviluppato presso i Bell Laboratories, un tempo parte del gigante delle telecomunicazioni AT&T. Progettato negli anni '70 per i computer PDP della Digital Equipment, è diventato un sistema operativo multiutente e multitasking molto popolare, disponibile per una gran varietà di piattaforme hardware, dalle workstation fino a server multiprocessori e supercomputer. Nel 1965, i Bell Telephone Laboratories unirono i loro sforzi a quelli della General Electric Company nel progetto MAC del MIT (Massachussets Institute of Technology) per sviluppare un nuovo Sistema Operativo. Il nome di quest'ultimo era Multics, acronimo di Multiplexed Information and Computing Service, dove ``multiplexed'' si riferisce alla combinazione di più segnali elettronici in un unico segnale. Si voleva far accedere simultaneamente un'ampia comunità di utenti al computer, fornire una grande potenza di calcolo e permettere agli utenti di condividere facilmente i loro dati, se necessario. Nel 1969, su un computer GE 645 girava una versione primitiva di Multics, che però non forniva il servizio computazionale che ci si era proposti inizialmente; inoltre non era chiaro quando sarebbe terminato il progetto, anche perché le tre entità coinvolte avevano obiettivi diversi. Quindi i Laboratori Bell abbandonarono il progetto, rimanendo però senza un Sistema Operativo adatto al lavoro da svolgere. Per migliorare l'ambiente di programmazione disponibile, Ken Thompson, Dennis Ritchie e altri abbozzarono il progetto di un file system, la cui successiva evoluzione condusse a una prima versione del file system di UNIX. Thompson scrisse dei simulatori del comportamento del file system proposto e dei programmi in un ambiente demand-paging, oltre a un semplice kernel per il computer GE 645. Allo stesso tempo, scrisse un programma in FORTRAN di nome ``Space Travel'', per un sistema GECOS (Honeywell 635), ma il programma era insoddisfacente perché era difficile controllare la ``navicella spaziale'' e il costo dell'esecuzione era eccessivo. Successivamente Thompson trovò un computer DEC (Digital Equipment Corporation) PDP-7 scarsamente usato, che offriva un buon display grafico ed era economico in termini di potenza richiesta per l'esecuzione. Il porting di Space Travel sul PDP-7 permise a Thompson di familiarizzare con quel computer, il cui ambiente di sviluppo software però richiedeva l'utilizzo del crossassembly sulla macchina GECOS e il trasporto del nastro magnetico, che serviva da input per il PDP-7. Per ottenere un ambiente di programmazione migliore, Thompson e Ritchie implementarono il loro progetto sul PDP-7, includendo una prima versione del file system di UNIX, il sottosistema dei processi e un piccolo insieme di utilità Il nuovo sistema così ottenuto era autoconsistente, non richiedendo il GECOS come ambiente di sviluppo, e fu chiamato Unics, come gioco di parole sul nome di Multics, coniato da un altro membro del Computing Science Research Center, Brian Kernighan. 8

Figura 1.1: Dennis Ritchie e Ken Thompson (seduto) sviluppano un sistema operativo general purpose per computer che può gestire una varietà di applicazioni dalla gestione di una rete di telecomunicazioni ad un word processor. UNIX è il primo software progettato per funzionare su computer di tutte le dimensioni da differenti produttori. E' il cuore di molti sistemi operativi che fanno funzionare la rete di telecomunicazioni della nazione, inclusa internet, Tale nome evidenziava il fatto che il sistema in questione era più piccolo e meno ambizioso di Multics e, almeno inizialmente, era monoutente; inoltre, ogni parte del sistema era progettata per svolgere al meglio un unico compito. Unics stava per ``UNiplexed Information and Computing System''; tale nome fu presto cambiato in Unix. 9

Che cos'è Linux Linux è una implementazione liberamente distribuibile di un kernel simil-unix, il nucleo a basso livello di un sistema operativo. Poiché Linux si ispira al sistema UNIX, i programmi per Linux e UNIX sono molto simili. Infatti, quasi tutti i programmi scritti per UNIX possono essere compilati ed eseguiti sotto Linux. Inoltre, molte applicazioni commerciali vendute per UNIX possono essere eseguite senza modifiche in forma binaria sui sistemi Linux. Linux fu sviluppato da Linus Torvalds 2 quando era studente alla Università di Helsinki, con l'aiuto dei programmatori UNIX tramite internet. Divenne poi un hobby inspirato dal sistema Minix di Andy Tanenbaum, un piccolo sistema UNIX, ma è cresciuto fino a diventare un completo sistema UNIX. Il kernel di Linux non usa il codice originale di UNIX di AT&T o qualsiasi altro codice proprietario. 2 Quando Linus Torvalds era studente all'università di Helsinki, stava usando una versione del sistema operativo UNIX chiamato 'Minix'. Linus ed altri utenti fecero delle richieste di modifiche e miglioramenti al creatore di Minix, Andrew Tanenbaum, ma questi riteneva che non fossero necessarie. Fu così che Linus decise di creare il suo proprio sistema operativo che avrebbe preso in considerazione i commenti ed i suggerimenti di miglioramento degli utenti. 10

Crono storia della nascita di un pinguino 01/07/91 Tutto inizia in un'estate finlandese, Linus Benedict Torvalds, ancora un giovane studente dell' Università di Helsinki, inizia a lavorare al suo hobby: Linux. Il 3 Luglio lo si sente informarsi su usenet: "Hello netlanders, Due to a project I'm working on (in minix), I'm interested in the posix standard definition. Could somebody please point me to a (preferably) machine-readable format of the latest posix rules? Ftpsites would be nice. " Torvalds giustificherà poi la folle impresa con queste parole: "I couldn't afford some of the commercial OSes and I didn't want to run DOS or Windows -- I don't even know, did Windows really exist then?". 5 Ottobre 1991 Nello stesso anno viene rilasciata la versione 0.02. Il post su usenet che ne annuncia la presenza è diventato un classico. Grazie all'archivio di 20 anni di storia di Usenet su Google possiamo ricordare. Gennaio 1992 Viene rilasciata la versione 0.12. Risulta relativamente stabile e supporta vario hardware. Da questa versione in poi la crescita di Linux inizia a diventare progressiva e dirompente, sia come numero di coder che supportano lo sviluppo, sia come utilizzatori. "Earlier kernel releases were very much only for hackers: 0.12 actually worked quite well" Aprile 1992 Rilasciate la versione 0.95 e 0.96. Il salto è diretto dalla 0.12. Nascono le prime distribuzioni: la MCC Linux e la SLS. 1994 Viene rilasciata la prima versione definitiva 1.0. Nascono RedHat, Debian, SUSE tutt'ora fra le distribuzioni più diffuse. Linux, che resta protetto da copyright da Linux Torvalds, diventa ufficialmente un software aperto, abbracciando in pieno la General Public License (GPL) del movimento GNU Open Source. Grazie all'aumento esponenziale dell'interesse da parte della comunità mondiale nascono i primi LUGs (Linux User Groups), ormai diffusi anche in Italia. 1995 Compaiono sul mercato delle nuove distribuzione commerciali come Caldera Linux. Kernel 1.2 in Marzo. Dal kernel 1.3 in sviluppo si passerà direttamente al 2.0 1996 Rilasciata la versione 2.0. Compaiono le prime versioni tradotte in più lingue. Linux ha bisogno di una mascotte: nasce TUX, il pinguino più famoso del mondo. 11

1997 Da qui in poi la storia di Linux diventa sempre più Linus indipendente, nel 1997 lascia la Finlandia per raggiungere Santa Clara, Silicon Valley, dove lo aspetta, nella misteriosa start-up Transmeta, un ruolo che ai più non è chiaro. Per anni, prima di annunciare al pubblico di produrre microprocessori a basso consumo e quotarsi al NASDAQ, Transmeta rimane un segreto impenetrabile intorno al quale si accumulano rumours e misteri: - E' la società dove lavora Linus Torvalds (che continua a sviluppare Linux e non si capisce per cosa venga pagato) - Fra i soci finanziatori figura Paul Allen (Microsoft co-founder) - Assume programmatori e tecnici di altissimo livello - Sfoggia per anni una home page che è un capolavoro di anti-marketing. 1999 Dopo lunga attesa il kernel 2.2 vede la luce. 2001 Agli inizi dell'anno, dopo varie pre-version, su kernel.org appare l'immagine da 19.788.626 byte del 2.4.0 La prima release di un altro stable thread. 2002 - Linux è una reale alternativa al mondo Microsoft e Unix, si ritrova milioni di utenti, migliaia di sviluppatori e un mercato in espansione. E' presente in sistemi integrati, è usato per il controllo di dispositivi robotizzati e ha volato a bordo dello Shuttle, praticamente gira su oggetti elettronici di tutti i tipi, dai palmari alle workstation Alpha, risultando l'os in assoluto il sistema operativo più soggetto a porting. Nessuno ormai si sogna di considerarlo un progetto sperimentale che non possa essere usato in applicazioni mission-critical, IBM "lo monta sui suoi server" (e lo pubblicizza pure), Microsoft lo considera il principale nemico da combattere (e non lesina risorse nel farlo), Oracle ci fa girare sopra il suo DB. 2003 - Le guerre si combattono per il petrolio e, più sotterraneamente, per il controllo dei computer. Il 2003 sarà ricordato anche per l'anno di SCO e dei suoi attacchi a Linux e al mondo OpenSource, consequenziali ad una azione legale intrapresa contro IBM. Le modalità degli attacchi, la loro natura, il modo con cui si cerca creare FUD intorno a Linux (Fear Uncertainty and Doubt) sono sintomo di interessi che vanno oltre la protezione di presunte proprietà intellettuali per parti di codice che vengono nominate ma non mostrate sembrano delinearsi come un banco di prova decisivo per la definitiva affermazione di Linux anche sul lato desktop e per un cambio paradigmatico su come viene valorizzato e diffuso il software. Tecnologicamente la strada è chiara e le carte sono vincenti: Linux e tutto il software OpenSource sono decisamente all'altezza sia sui sistemi di fascia alta che sui desktop, oltre ad essere presente nel cuore invisibile di innumerevoli device elettronici. 2004 - Sgonfiato, anche se non concluso, il caso SCO, nuove minacce si profilano all'orizzonte di un pinguino che continua a diffondersi e conquistare nuovi territori: in particolare leggi draconiane sui brevetti, 12

che permettono di brevettare indiscriminatamente algoritmi, soluzioni e idee informatiche triviali e ampiamente diffuse, o soluzioni tecniche tali da rendere impossibile o soggetta a una fee arbitraria l'interoperabilità fra sistemi operativi. Intanto il kernel 2.6 si diffonde e viene usato nelle principali distribuzioni, sempre più user friendly e pronte per il desktop. E' una guerra, più o meno dichiarata, i cui i nemici spesso mostrano una faccia sorridente e colpiscono su campi e livelli che non hanno nulla a che vedere con l'innovazione e l'eccellenza tecnica. 13

Il progetto GNU e la Free Software Foundation Linux deve la sua esistenza allo sforzo cooperativo di un gran numero di persone. Lo stesso nucleo del sistema operativo forma solo una piccola parte di un sistema di sviluppo utilizzabile. I sistemi UNIX commerciali tradizionalmente vengono venduti insieme a programmi applicativi che forniscono strumenti e servizi di sistema. Per i sistemi Linux, questi programmi aggiuntivi sono stati scritti da tanti programmatori diversi e sono stati liberamente distribuiti. La comunità Linux (insieme ad altre) supporta il concetto di free software, cioè software che sia libero da restrizioni, soggetto alla licenza GNU General Public License. Sebbene ci possa essere un costo per ottenere il software3, successivamente esso può essere usato in qualsiasi modo si desideri, e normalmente viene distribuito in formato sorgente. La Free Software Foundation fu creata da Richard Stallman, l'autore di GNU Emacs, uno dei più conosciuti editor per UNIX ed altri sistemi. Stallman è un pioniere del concetto di free software e cominciò il progetto GNU, un tentativo di creare un sistema operativo ed ambiente di sviluppo che sarà compatibile con UNIX. Il nome GNU sta per GNU's Not Unix. 3 Costo dovuto alle spese per la sua distribuzione 14

La Shell La shell4 è l'interprete dei comandi proprio dei sistemi Unix, un programma, cioè, che legge ed interpreta i comandi che vengono inseriti dall'utente. La sua esecuzione comincia dopo il completamento da parte dell'utente delle procedure di login; scrive un prompt5 (di solito uno dei due caratteri '$' o '%'), si mette in attesa di un comando, lo esegue e torna in attesa di un nuovo comando, fino a che l' utente non termina la sessione. L' utente può interagire con la shell secondo tre modalità: - interattiva: quando richiama i comandi del sistema. - di programmazione: quando crea nuove sequenze di comandi attraverso frasi e variabili proprie della shell stessa. - di personalizzazione del proprio ambiente operativo: quando predispone i files di inizializzazione e terminazione delle sessioni di lavoro, o le variabili utilizzate dai programmi di sistema. 4 5 La shell è una utilità che abilita l'utente ad interagire con il sistema operativo UNIX. I comandi introdotti dall'utente sono passati dalla shell al sistema operativo, che li esegue. I risultati sono poi ripassati dalla shell e visualizzati sullo schermo dell'utente. È il carattere (o l'insieme di caratteri) all'inizio della riga di comando che indica che il computer (la shell) è pronto a ricevere ed eseguire un comando. Il carattere di solito è un '%' (segno percentuale) o un $ (segno di dollaro). 15

La shell ed il sistema operativo In informatica, una shell è un pezzo di software che essenzialmente fornisce una specie di interfaccia per gli utenti finali. Tipicamente, il termine si riferisce alla shell di un sistema operativo che fornisce l'accesso ai servizi di un kernel. Comunque, il termine viene anche utilizzato in maniera lasca alle applicazioni e può includere qualsiasi software che sia costituito "attorno ad" un componente particolare come i browser web ed i clienti di posta elettronica, che sono "shell" per i motori di rendering dell'html6. Il nome 'shell' origina da shell essendo uno strato esterno tra l'utente e le parti interne di un sistema operativo (il kernel). Le shell di un sistema operativo ricadono generalmente in due categorie: riga di comando e grafica. Le shell a riga di comando forniscono una interfaccia a riga di comando (CLI: Command line interface) al sistema operativo, mentre le shell grafiche forniscono una interfaccia grafica utente (GUI: graphical user interface). I meriti relativi delle shell CLI e delle shell basate su GUI sono spesso soggetto di dibattiti. I fautori di CLI reclamano che certe operazioni possono essere eseguite molto più velocemente sotto shell di testo (CLI), come spostare file, ad esempio, che sotto shell GUI. Comunque, i fautori delle GUI insistono sulla facilità ed usabilità delle shell grafiche (GUI). 6 Hyper Text Markup Language 16

La scelta migliore è spesso determinata dal modo in cui un computer sarà usato. Su un server, usato principalmente per l'elaborazione ed il trasferimento dei dati con una amministrazione esperta, una CLI probabilmente è la scelta migliore. Dall'altro lato, un sistema grafico (GUI) probabilmente sarebbe più appropriato per un computer da usare per l'elaborazione grafica o video. 17

Tipi di shell Così come la gente conosce differenti linguaggi e dialetti, così un sistema UNIX offrirà usualmente una varietà di tipi di shell: 1. sh o Bourne Shell: la shell originale ancora usata sui sistemi UNIX e negli ambienti correlati ad UNIX. Questa è la shell di base, un piccolo programma con poche caratteristiche. Anche se non è la shell standard, è ancora disponibile su ogni sistema Linux per compatibilità con i programmi UNIX. 2. bash o Bourne Again shell: la shell standard del sistema GNU, intuitiva e flessibile. Probabilmente consigliabile per gli utenti alle prime armi anche se allo stesso tempo è uno strumento potente per l'utente avanzato e professionista. Su Linux, bash è la shell di riferimento per i comuni utenti. Questa shell è un superset della shell di Bourne, un insieme di add-on e plug-in. Questo significa che bash (Bourne Again shell) è compatibile con la shell di Bourne: i comandi che funzionano in sh, funzionano anche in bash. Comunque, non è sempre vero il contrario. 3. csh o C shell: la sintassi di questa shell somiglia a quella del linguaggio C. 4. tcsh o Turbo C shell: un superset della comune C shell, che migliora la facilità d'uso (userfriendliness) e la velocità. 5. ksh o Korn shell: a volte apprezzata dalle persone con una preparazione di UNIX. Un superset della shell di Bourne; un incubo per gli utenti alle prime armi. 18

Shell come interprete di comandi Nella sua funzione più comune la shell agisce come interprete di comandi semplici, cioè di comandi costituiti di una o più parole separate da spazi, delle quali la prima specifica il comando da eseguire, le altre se presenti sono passate come argomenti al comando. La shell riconosce però alcuni caratteri particolari detti metacaratteri che non sono passati inalterati al comando, ma che essa stessa riconosce come richieste di attivazione di modalità operative particolari. L' esecuzione di un comando in background, ad esempio, viene attivata concludendo il comando con il metacarattere &: in questo caso la shell manda in esecuzione l'istruzione "ripulita" da &, in quanto lo scopo del metacarattere era quello di comunicare alla shell di attivare l' esecuzione in background. L' interazione tra shell e comando richiesto si conclude con la restituzione, da parte di quest'ultimo, del valore numerico zero in caso positivo, e di un valore diverso da zero in caso di fallimento. Attivazione della shell Come si attiva la shell? Se ci troviamo in ambiente grafico (KDE, ad esempio), sul pannello, nella parte inferiore dello schermo, clicchiamo sull'icona del terminale: Terminale Quello che viene attivato è il programma Konsole, un emulatore di terminale in ambiente grafico XWindows. 19

I sistemi operativi UNIX in origine erano progettati come sistemi solo testo, non esistevano ancora le interfacce grafiche odierne, ed erano controllati da comando della tastiera quello che si chiama interfaccia a riga di comando (CLI, ovvero Command-Line Interface). Il sistema X Window, KDE ed altri progetti hanno aggiunto l'interfaccia grafica che usiamo oggigiorno. Ad ogni modo, il sottostante sistema CLI è ancora al suo posto ed è il modo più facile, veloce e potente di eseguire molti compiti. Il programma Konsole è ciò che è conosciuto con il nome di emulatore di terminale X, al quale ci si riferisce spesso come terminale o shell. 20

Input/Output standard e redirezione dell'i/o Standard Input e Standard Output Molti dei comandi UNIX ricevono l'input dal terminale ed inviano il risultante output indietro al terminale. Un comando normalmente legge il suo input da un posto chiamato standard input, che per default è il terminale. In modo simile, un comando normalmente scrive il suo output sullo standard output, che per default è sempre il terminale. Figura : Tipica esecuzione di un comando UNIX Il comando who, ad esempio, visualizza gli utenti attualmente connessi. Più formalmente, il comando who scrive sullo standard output (che sarebbe lo schermo) la lista degli utenti connessi. 21

In un programma scritto in C, le istruzioni di lettura, come ad esempio scanf, gets, ecc. si riferiscono alla tastiera come allo standard input, e le istruzioni di scrittura, ad esempio printf, puts, ecc. si riferiscono allo schermo come standard output. In Linux (e nel linguaggio di programmazione C) la tastiera, lo schermo, ecc. sono tutti trattati come file. Nella tabella che segue ci sono i nomi di tali file. Per default, in Linux ogni programma ha associato con esso almeno tre file, (quando facciamo eseguire un programma, questi tre file sono automaticamente aperti dalla shell in uso). Standard File File Descriptors number stdin 0 come Standard input stdout 1 come Standard output Video stderr 2 come Standard error Video Uso Esempio Keyboard 22

Programmazione della shell Perché programmare la shell? La conoscenza pratica dello scripting di shell è essenziale per coloro che desiderano diventare degli amministratori di sistema esperti, anche se mai avrebbero messo in preventivo di scrivere degli script. Occorre tener presente che quando viene avviata una macchina Linux, questa esegue gli script di shell contenuti nel file /etc/rc.d per ripristinare la configurazione del sistema ed attivarne i servizi. La comprensione dettagliata degli script di avvio è importante per analizzare il comportamento di un sistema e, se possibile, modificarlo. Perché apprendere la Shell? Il progettista di un programma che fornisce una interfaccia utente grafica (GUI) deve anticipare tutti i possibili modi in cui l'utente interagirà con il programma e fornisce i modi per catturare le appropriate risposte del programma a causa del puntare e cliccare. Conseguentemente, l'utente è costretto a lavorare solo nei modi previsti. L'utente perciò è incapace di adattare l'interfaccia del programma per risolvere circostanze non previste. In poche parole, è questa la ragione per cui molti compiti degli amministratori di sistema sono svolti usando la shell: gli amministratori di sistema, nell'adempiere alle proprie responsabilità di mantenere un sistema funzionante, devono continuamente trattare con e vincere l'imprevisto. Imparare a scrivere degli script non è difficile, perché possono essere costituiti da sezioni di piccole dimensioni ed è veramente esigua anche la serie di operatori ed opzioni specifiche che è necessario conoscere. La sintassi è semplice e chiara, come quella necessaria per eseguire e concatenare utilità da riga di comando, e sono poche anche le "regole" da imparare. Nella maggior parte dei casi, gli script di piccole dimensioni funzionano correttamente fin dalla prima volta che vengono eseguiti e non è complicata neanche la fase di debugging di quelli di dimensioni maggiori. Uno script di shell è un metodo "rapido e grezzo" per costruire un prototipo di un'applicazione complessa. Far eseguire anche una serie ridotta di funzionalità tramite uno script di shell è spesso un utile primo passo nello sviluppo di un progetto. In questo modo si può verificare e sperimentare la struttura di un'applicazione e scoprire i principali errori prima di procedere alla codifica finale in C, C++, Java o Perl. Lo scripting di shell è attento alla filosofia classica UNIX di suddividere progetti complessi in 23

sezioni di minori dimensioni che svolgono un compito particolare, concatenando componenti e utilità Questo è considerato, da molti, un approccio migliore, o almeno esteticamente più piacevole per risolvere un problema, che utilizzare uno dei linguaggi di nuova generazione, come Perl, che offrono funzionalità per ogni esigenza, ma al prezzo di costringere a modificare il modo di pensare un progetto per adattarlo al linguaggio utilizzato. Quando non usare gli script di shell -In compiti che richiedono un utilizzo intenso di risorse, specialmente quando la velocità è un fattore determinante (ordinamenti, hashing, ecc.) -In procedure che comprendono operazioni matematiche complesse, specialmente aritmetica in virgola mobile, calcoli in precisione arbitraria o numeri complessi (si usi C++ o FORTRAN) È necessaria la portabilità (si usi, invece, il C o Java) - In applicazioni complesse dove è necessaria la programmazione strutturata (necessità di tipizzazione delle variabili, prototipi di funzione, ecc.) - In applicazioni particolari su cui si sta rischiando il tutto per tutto, o il futuro della propria azienda In situazioni in cui la sicurezza è importante, dove occorre garantire l'integrità del sistema e proteggerlo contro intrusioni, cracking e vandalismi In progetti costituiti da sotto-componenti con dipendenze interconnesse Sono richieste operazioni su file di grandi dimensioni (Bash si limita ad un accesso sequenziale ai file, eseguito riga per riga e in un modo particolarmente goffo ed inefficiente) E' necessario il supporto nativo per gli array multidimensionali Sono necessarie strutture di dati quali le liste collegate o gli alberi E' necessario generare o manipolare grafici o GUI È necessario un accesso diretto all'hardware del sistema È necessaria una porta o un socket I/O È necessario l'utilizzo di librerie o interfacce per l'esecuzione di vecchio codice In applicazioni proprietarie a codice chiuso (il codice sorgente degli script di shell è aperto e tutti lo possono esaminare) 24

Che cos'è uno script di shell? * Un file di testo contenente comandi che avrebbero potuto essere scritti direttamente nella shell. * La stessa shell ha limitate capacità -- la sua potenza deriva dall'usarla come linguaggio collante per combinare i comandi standard di Unix ed il software dell'utente, per produrre uno strumento più utile che i componenti presi da soli. * Una qualsiasi shell può essere utilizzata per scrivere uno script di shell. Per fare ciò, la prima riga di ogni script deve essere: #!/percorso/alla/shell ad esempio #!/bin/bash * Qualsiasi file può essere usato come input della shell usando la sintassi: bash mioscript Se il file è reso eseguibile usando il comando chmod, esso diventa un nuovo comando e disponibile all'uso Esempio: chmod +x mioscript Uno script di shell può essere tanto semplice come una sequenza di comandi che scriviamo regolarmente. Mettendoli in uno script, li riduciamo ad un singolo comando 25

Gli operatori aritmetici e relazionali della shell Bash Gli operatori aritmetici che si possono usare nella shell sono i seguenti: - operando inverte il segno dell'operando operando1 + operando2 somma i due operandi operando1 - operando2 differenza tra i due operandi operando1 * operando2 prodotto tra i due operandi operando1 / operando2 divisione intera tra i due operandi operando1 % operando2 calcola il modulo, cioè il resto della divisione tra il primo ed il secondo operando Gli operatori relazionali che si possono usare nella shell sono i seguenti: -lt (abbreviazione di less than) equivale al test < Es. a -lt b verifica se a < b -gt (abbreviazione di greater than) equivale al test > Es. a -gt b verifica se a>b -le (abbreviazione di less than or equal to) equivale al test <= Es. a -le b verifica se a<=b -ge (abbreviazione di greater than or equal to) equivale al test >= Es. a -ge b verifica se a>=b -eq (abbreviazione di equal to) equivale al test == Es. a -eq b verifica se a==b -ne (abbreviazione di not equal to) equivale al test!= Es. a -ne b verifica se a!=b 26

Programmazione della shell: le strutture di ripetizione Nella shell di Bash abbiamo a disposizione varie strutture di ripetizione, che sono implementate attraverso i seguenti costrutti: -while -until -for Il ciclo while La sintassi della struttura while ha il seguente formato: while [ condizione ] do comandi/istruzioni done Il ciclo while permette di ripetere tutti i comandi o le istruzioni comprese tra do e done finché la condizione specificata tra le parentesi quadre rimane verificata, ovvero mantiene il valore logico vero. Affinché il ciclo abbia termine, la condizione ad un certo punto non deve essere più verificata. Esempio: #!/bin/bash # Ciclo infinito i=0 while [ $i -eq 0 ] do echo $i done 27

Questo ciclo non termina mai. Per interrompere l'esecuzione, usiamo la combinazione di tasti CTRL+c Il ciclo seguente invece termina subito dopo aver stampato il valore della variabile i: #!/bin/bash # Ciclo finito i=0 while [ $i -eq 0 ] do echo $i i=1 done Attenzione! La condizione tra le parentesi quadre deve essere scritta lasciando uno spazio a destra ed uno spazio a sinistra. Ad esempio: #!/bin/bash # Ciclo infinito i=0 while [$i -eq 0] do echo $i done se facciamo eseguire questo script otteniamo il seguente messaggio di errore: [0: command not found 28

Esercizio Stampare i primi 10 numeri naturali 1, 2, 3, 4, 5, 6, 7, 8, 9 10 Vediamo di applicare quanto spiegato sui cicli di while per risolvere il seguente semplicissimo problema: stampare i primi 10 numeri naturali 1, 2, 3, 4, 5, 6, 7, 8, 9 10 Abbiamo già risolto il problema usando il linguaggio C, e quindi l'algoritmo non dovrebbe essere del tutto sconosciuto, oltre ad essere anche banale. Veniamo al dunque. Quello che ci serve è una variabile, diciamo i, che parte da 1 ed arriva a 10, stampata e poi incrementata man mano. #!/bin/bash # Inizializziamo la variabile contatore i i=1 la condizione da verificare è i<=10, che scriveremo come: $i -le 10 Partiamo poi ad eseguire il ciclo while [ $i -le 10 ] do Stampiamo il contenuto della variabile i: echo $i Incrementiamo la variabile i: let i=$(($i+1)) 29

done Ecco lo script completo #!/bin/bash i=1 while [ $i -le 10 ] do echo $i let i=$(($i+1)) done Scriviamo con un editor di testo lo script, lo salviamo con il nome ciclo_stampa.sh, impostiamo poi i permessi di esecuzione con chmod u+x ciclo_stampa.sh e lo mandiamo in esecuzione con./ciclo_stampa.sh 30

ESERCIZIO L'esercizio che svolgeremo ora è una piccola modifica dell'esercizio precedente, e cioè stampare i primi N numeri naturali 1, 2, 3,..., N, dove però l'ultimo numero da stampare è variabile. Invece nell'esercizio precedente era sempre fissato a 10. Useremo una seconda variabile, N, dove memorizziamo l'estremo superiore della sequenza da stampare. Come abbiamo già detto, l'algoritmo non dovrebbe essere del tutto sconosciuto, oltre ad essere anche banale. Veniamo al dunque. Quello che ci serve è una variabile, diciamo i, che parte da 1 ed arriva a N, stampata e poi incrementata man mano. In questa versione Inizializziamo N ad un valore a scelta, ad esempio N=15 #!/bin/bash # Inizializziamo la variabile contatore i i=1 31

# Inizializziamo la variabile N N=15 la condizione da verificare è i<=n, che scriveremo come: $i -le N Partiamo poi ad eseguire il ciclo while [ $i -le $N ] do Stampiamo il contenuto della variabile i: echo $i Incrementiamo la variabile i: let i=$(($i+1)) done Ecco lo script completo #!/bin/bash i=1 N=15 while [ $i -le $N ] do echo7 $i let i=$(($i+1)) done Scriviamo con un editor di testo lo script, lo salviamo con il nome ciclo_stampa2.sh, impostiamo poi i permessi di esecuzione con chmod u+x ciclo_stampa2.sh e lo mandiamo in esecuzione con./ciclo_stampa2.sh 7 Il comando echo visualizza un messaggio sullo schermo, inviando ogni stringa allo standard output, e terminando con un newline 32

Visualizzare l'output: il comando echo Negli esercizi precedenti abbiamo iniziato ad usare il comando echo. Il comando visualizza un messaggio sullo schermo, inviando ogni stringa allo standard output, e terminando con un newline. Ad esempio, il comando echo pere mele banane visualizza sullo schermo le tre parole pere mele banane Ma il comando echo è molto più potente ed ha varie opzioni che arricchiscono la sua funzionalità. Supponiamo ad esempio di voler sopprimere il newline 8. Consideriamo il seguente script che stampa sul video la tabellina pitagorica: #!/bin/bash #Tabellina pitagorica i=1 8 Carattere speciale per stampare su una nuova riga 33

while [ $i -le 10 ] do j=1 while [ $j -le 10 ] do #calcola il prodotto i*j let p=$(($i*$j)) #stampa il prodotto i*j echo $p #incrementa la variabile j let j=$(($j+1)) done #incrementa la variabile i let i=$(($i+1)) #stampa una nuova riga echo done Se usiamo il comando echo nella sua forma più semplice, senza alcuna opzione, non potremo evitare che ogni numero venga stampato su una riga diversa, quindi avremo la tabellina stampata su 100 righe! Per evitare che il comando echo stampi ogni dato su una riga diversa, dobbiamo sopprimere l'emissione della nuova riga ogni volta che viene inviato sull'output standard un nuovo dato. Cioè, dobbiamo stampare tutti i dati su una stessa riga. L'opzione -n aggiunta al comando echo evita di eseguire un newline alla fine della stampa. Modifichiamo allora il nostro script. #!/bin/bash #Tabellina pitagorica i=1 while [ $i -le 10 ] do j=1 while [ $j -le 10 ] do let p=$(($i*$j)) echo -n $p let j=$(($j+1)) done let i=$(($i+1)) echo done E vediamo l'output di questo nuovo script: 12345678910 34

2468101214161820 36912151821242730 481216202428323640 5101520253035404550 612182430ù3642485460 7142128354249566370 8162432404856647280 9182736455463728190 102030405060708090100 Un poco disordinato! Cerchiamo di separare i numeri. Aggiungiamo uno spazio vuoto trai numeri: #!/bin/bash #Tabellina pitagorica i=1 while [ $i -le 10 ] do j=1 while [ $j -le 10 ] do let p=$(($i*$j)) echo -n " " $p let j=$(($j+1)) done let i=$(($i+1)) echo done Vediamo il risultato dell'esecuzione dello script: 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 Ci vorrebbe un'opzione per poter distanziare i numeri. Bisognerebbe poter aggiungere un carattere di tab dopo ogni numero. Il comando echo permette di usare il carattere di tabulazione '\t', ma bisogna abilitarlo, con l'opzione -e Ovvero il comando echo si scriverà come: echo -ne dato da visualizzare Ecco come modificheremo il nostro script 35

#!/bin/bash #Tabellina pitagorica i=1 while [ $i -le 10 ] do j=1 while [ $j -le 10 ] do let p=$(($i*$j)) echo -ne '\t' $p let j=$(($j+1)) done let i=$(($i+1)) echo done Ed ecco l'output ottenuto dall'esecuzione dello script: 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 4 5 6 7 8 9 10 6 8 10 12 14 16 18 20 9 12 15 18 21 24 27 30 12 16 20 24 28 32 36 40 15 20 25 30 35 40 45 50 18 24 30 36 42 48 54 60 21 28 35 42 49 56 63 70 24 32 40 48 56 64 72 80 27 36 45 54 63 72 81 90 30 40 50 60 70 80 90 100 Ed è proprio quello che volevamo! 36

Il ciclo while e il ciclo di for Essenzialmente esistono due tipi di cicli (strutture iterative): -ciclo while -ciclo for La sintassi del ciclo while è la seguente: while [ condizione ] do istruzioni done Attenzione! Lasciare uno spazio tra while e la prima parentesi quadra ed all'interno della parentesi quadra, uno spazio prima e dopo la condizione. La sintassi del ciclo for è la seguente: for dato in Lista do istruzioni done Il ciclo di for nella shell BASH è completamente diverso dal ciclo di for del linguaggio C. Durante ogni passo attraverso il ciclo, la variabile dato prende il valore di ogni variabile presente nella lista. La lista può essere un elenco qualsiasi, un array, un elenco di stringhe, un elenco di variabili, ecc. Esempio 1 #!/bin/bash for giorno in "Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato","Domenica" do echo "Oggi è "$giorno done Lo stesso ciclo di prima, ma scritto in modo differente. Eseguite i due script, e annotate le differenze. Esempio 2 #!/bin/bash for giorno in Lunedì Martedì Mercoledì Giovedì Venerdì Sabato Domenica do 37

echo "Oggi è "$giorno done Esempio 3 #!/bin/bash #pianeti.sh #Visualizza l'elenco dei pianeti del sistema solare echo "I pianeti del sistema solare" for pianeta in Mercurio Venere Terra Marte Giove Saturno Uranio Nettuno Plutone do echo $pianeta done La lista può anche essere un array: #!/bin/bash #pianeti.sh #Visualizza l'elenco dei pianeti del sistema solare declare -a pianeti echo "I pianeti del sistema solare" pianeti=( Mercurio Venere Terra Marte Giove Saturno Uranio Nettuno Plutone ) for pianeta in ${pianeti[*]} do echo $pianeta done Ricordiamo che per riferirci a tutto il contenuto di un array, scriveremo sempre: ${nome_array[*]} nel nostro caso: ${pianeti[*]} Il ciclo While Il ciclo while permette di ripetere tutti i comandi o le istruzioni comprese tra do e done finché la condizione specificata tra le parentesi quadre rimane verificata, ovvero mantiene il valore logico vero. Affinché il ciclo abbia termine, la condizione ad un certo punto non deve essere più verificata. Esempio: 38

#!/bin/bash # Ciclo infinito i=0 while [ $i -eq 0 ] do echo $i done Questo ciclo non termina mai. Per interrompere l'esecuzione, usiamo la combinazione di tasti CTRL+c Il ciclo seguente invece termina subito dopo aver stampato il valore della variabile i: #!/bin/bash # Ciclo finito i=0 while [ $i -eq 0 ] do echo $i i=1 done Attenzione! La condizione tra le parentesi quadre deve essere scritta lasciando uno spazio a destra ed uno spazio a sinistra. Ad esempio: #!/bin/bash # Ciclo infinito i=0 while [$i -eq 0] do echo $i done se facciamo eseguire questo script otteniamo il seguente messaggio di errore: [0: command not found Esercizio di programmazione in bash: verifica se un'equazione di secondo grado ha radici reali o complesse e coniugate Da notare come si eseguono le operazioni aritmetiche. In bash si usa una tecnica particolare. Tutta l'espressione deve essere racchiusa da una doppia coppia di parentesi, il tutto preceduto dal segno di 39

dollaro ($). Ad esempio: # Assegna i valori alle variabili a e b a=1 b=2 # Calcola l'espressione $a+$b e l'assegna alla variabile c let c=$(($a+$b)) # Visualizza il contenuto della variabile c echo $c Listato dello script risolvi.sh #!/bin/bash #Nome Script: risolvi.sh #Scopo: Verifica se un'equazione di secondo grado ha radici reali o complesse e coniugate #Uso./risolvi.sh A B C #Es../risolvi.sh 1 2 1 declare A declare B declare C declare Delta # Lettura degli argomenti dalla riga di comando A=$1 B=$2 C=$3 #Stampa di prova degli argomenti letti echo A=$A echo B=$B echo C=$C #Stampa di prova del valore calcolato di Delta let Delta=$(($B*$B-4*$A*$C)) echo Delta=$Delta if [ $Delta -ge 0 ] then echo "Radici reali e distinte" else echo "Radici complesse e coniugate" fi 40

Le variabili di sistema Parliamo di alcune variabili di sistema che assumono un ruolo particolare, diciamo speciale, nell'ambito della shell. La shell possiede queste variabili speciali: $# $* $? $$ La variabile $# La variabile $# rappresenta il numero dei parametri opzionali passati come argomento allo script. La variabile $* La variabile speciale $* rappresenta la lista dei parametri opzionali passati come argomento allo script. La variabile $? La variabile $?, seguita dal nome del comando, serve per determinare lo stato di uscita dall'ultimo comando eseguito dalla shell. Se il risultato è 0 significa che il comando si è concluso correttamente, un valore diverso da zero indica che il comando si è concluso con una situazione di errore. La variabile $$ La variabile $$ rappresenta il PID (Process IDentifier) del processo della shell, processo padre del comando in esecuzione. 41

Lettura dei dati: l'istruzione read L'istruzione read è una istruzione interna di bash, e come è facile intuire, serve per la lettura dei dati dal dispositivo standard di input (che in genere è la tastiera, ma questa situazione di default può essere cambiata). Nella sua forma più semplice l'istruzione read usa la seguente sintassi: read variabile ovvero assegna alla variabile il valore letto dal dispositivo standard di input (la tastiera). Ad esempio, proviamo il codice seguente: #!/bin/bash # script1.sh echo "input a1: " read a1 echo "input a2: " read a2 echo "a1 = " $a1 echo "a2 = " $a2 Lo script precedente legge prima la variabile tramite l'istruzione read a1 e poi legge la variabile a2 tramite l'istruzione read a2. Infine visualizza le due variabili sul dispositivo standard di output (lo schermo, in genere) echo "a1 = " $a1 echo "a2 = " $a2 42

43

Fornire i comandi alla Shell Quando la shell viene eseguita, visualizza un prompt sul terminale, di solito un segno di dollaro $, ed attende che l'utente scriva un comando. Ogni volta che l'utente inserisce il comando e preme il tasto INVIO, la shell analizza la riga inserita e la processa per completare la richiesta. Se l'utente chiede di eseguire un particolare programma, la shell ricerca sul disco finché non trova il programma invocato. Quando l'ha trovato, la shell chiede al kernel di iniziare l'esecuzione del programma, e poi la shell si mette a dormire finché l'esecuzione del programma non è terminata. Il kernel copia in memoria il programma specificato e comincia la sua esecuzione. Il programma copiato in memoria si chiama processo; in questo modo, viene fatta una distinzione tra il programma registrato in un file su disco ed un processo che si trova in esecuzione in memoria. 44

Filesystem di Linux Un filesystem comprende i metodi e le strutture dei dati usate da un sistema operativo per tenere traccia dei file su un hard disk o su una sua partizione, cioè il modo in cui i file sono organizzati sui dischi. La parola viene anche usata per riferirsi ad una partizione o a un disco usato per immagazzinare i file, o al tipo del filesystem stesso. Prima che si possa usare un disco o una partizione come filesystem, questo deve essere inizializzato e bisogna scriverci le strutture di dati per l'archiviazione: questo processo si chiama creazione di un filesystem. Un singolo hard disk può essere diviso in diverse partizioni, ciascuna delle quali funziona come se fosse un disco separato. L'idea è che se avete un hard disk e ad esempio volete avere due sistemi operativi, potete suddividere il disco in due partizioni; ciascun sistema operativo userà la sua partizione come vuole e non toccherà quella dell'altro. In questo modo i due sistemi possono coesistere sullo stesso hard disk, mentre senza le partizioni ci sarebbe voluto un disco per ciascun sistema operativo. I floppy non vengono partizionati, non per motivi tecnici, ma perché sono molto piccoli e creare al loro interno delle partizioni non sarebbe utile se non in casi molto rari. I CD-ROM di solito non vengono partizionati, dato che è molto più semplice usarli come un grande disco e in genere non è necessario avere diversi sistemi operativi sullo stesso CD-ROM. L'MBR, i settori di boot e la tabella delle partizioni Le informazioni sul partizionamento di un hard disk si trovano nel suo primo settore. Questo settore si chiama master boot record (MBR ) del disco. L'MBR è il settore che il BIOS legge ed avvia quando la macchina viene accesa. Il master boot record contiene un piccolo programma che legge la tabella delle partizioni, controlla quale partizione è attiva (cioè quale è contrassegnata come avviabile) e legge il primo settore di quella partizione, il boot sector (settore di avvio ) della partizione (anche l'mbr è un settore di avvio, ma ha uno status speciale e quindi un nome speciale). Il boot sector contiene un altro programmino che legge la prima parte del sistema operativo 45

contenuto in quella partizione (sempre che sia avviabile) e lo avvia. Il BIOS BIOS (pronunciato /ˈbaɪoʊs/), è l'abbreviazione di Basic Input/Output System. Il termine è scorrettamente conosciuto come Binary Input/Output System, Basic Integrated Operating System ed occasionalmente Built In Operating System. BIOS si riferisce al codice del firmware eseguito da un personal computer all'accensione. La funzione primaria del BIOS è di identificare ed inizializzare i componenti hardware, (come gli hard drive, floppy, e CD). Questo serve a preparare la macchina in modo tale che altri programmi memorizzati su mezzi diversi possano caricare, eseguire ed assumere il controllo del PC. Questo processo è noto come booting, o booting up, che è l'abbreviazione di bootstrapping. BIOS si può anche dire di un programma codificato inserito su un chip che riconosce e controlla vari dispositivi che costituiscono un personal computer. Tra le altre classi di computer, erano comunemente usati i termini boot monitor, boot loader o boot ROM. Il termine BIOS è comparso per la prima volta nel sistema operativo CP/M, descrivendo la parte di CP/M caricata durante la fase di boot che si interfacciava direttamente con l'hardware (le macchine CP/M avevano generalmente un semplice boot loader nella ROM, e niente altro). Molte versioni di DOS hanno un file chiamato "IBMBIO.COM" o "IO.SYS" che è analogo al BIOS su disco di CP/M. Come il BIOS viene caricato Il BIOS viene caricato da PROM, EPROM o, più comunemente, da flash memory quando il computer viene acceso. Esso inizializza parecchi componenti della motherboard e periferche, tra cui: Il generatore di clock. I processori e le cache. I chipset (controller della memoria ed i controller di I/O). La memoria di sistema. Tutti i dispositivi PCI (assegnando le risorse ed i numeri di bus). Il controller rimario della grafica. Controller della memoria di massa (come SATA ed i controller IDE). Vari controller di I/O (come tastiera/mouse e USB). 46

Infine, carica il boot loader per il sistema operativo, e trasferisce il controllo ad esso. L'intero processo è noto come power-on self-test (POST). Sull'originario IBM PC, l'hardware necessitava solo una configurazione minimale e POST veniva usato solo per la verifica; sui sistemi moderi, la maggior parte del POST consiste in realtà di configurazione hardware. Una volta che la memoria di sistema è inizializzata, il BIOS tipicamente copia/decomprime se stesso in quella memoria e continua l'esecuzione da esso. Quasi tutte le implementazioni BIOS possono opzionalmente eseguire un programma di setup interfacciante la memoria non volatile del BIOS (CMOS). Questa memoria mantiene i dati di configurazione definiti dall'utente (password, ora, data, dettagli dell'hard disk, ecc.) ai quali accede il codice del BIOS. Il codice sorgente in linguaggio macchina 80x86 del BIOS per i primi PC e AT fu incluso con il manuale "IBM Personal Computer Technical Reference Manual". Nella maggior parte delle moderne implementazioni del BIOS, l'utente decide dove il BIOS carica la sua immagine di boot: CD, hard disk, floppy disk, dispositivo USB o attraverso una connessione di rete. Ciò è particolarmente utile per installare sistemi operativi oppure fare il boot memorie flash o da LiveCD, e per selezionare l'ordine di verifica della presenza di un dispositivo avviabile. Alcuni BIOS consentono all'utente di selezionare il sistema operativo da caricare (es. caricare un altro sistema operativo dal secondo hard disk), sebbene questo sia più spesso gestito da un bootloader di secondo stadio. 47

Partizioni estese e partizioni logiche Lo schema di partizionamento originale degli hard disk dei PC permetteva solo quattro partizioni, ma presto questo si è dimostrato troppo poco per l'uso reale, perché alcune persone volevano più di quattro sistemi operativi (Linux, MS-DOS, OS/2, Minix, FreeBSD, NetBSD, o Windows NT, per nominarne alcuni), ma principalmente perché a volte è una buona idea avere diverse partizioni per un solo sistema operativo. Partizioni estese Per superare questo problema di progettazione, furono create le partizioni estese. Questo trucco permette di partizionare una partizione primaria in sotto-partizioni. La partizione primaria così suddivisa si dice estesa e le sottopartizioni sono partizioni logiche: si comportano come primarie ma vengono create in maniera diversa; non comportano una differenza di velocità. 48

La struttura delle partizioni di un hard disk Il disco viene diviso in tre partizioni primarie, la seconda delle quali è divisa in due partizioni logiche, e parte del disco non viene partizionato. Il disco intero e ciascuna partizione primaria hanno un settore di boot. Figura - Un esempio di partizionamento di hard disk. 49

Le informazioni rilevanti sulla tabella delle partizioni si ricavano dal comando fdisk -l: [root@www padrone]# fdisk -l /dev/hda Disk /dev/hda: 81.9 GB, 81964302336 bytes 16 heads, 63 sectors/track, 158816 cylinders Units = cilindri of 1008 * 512 = 516096 bytes Dispositivo Boot /dev/hda1 * /dev/hda2 /dev/hda5 /dev/hda6 /dev/hda7 /dev/hda8 /dev/hda9 /dev/hda10 /dev/hda11 Start 1 13991 13991 17241 35106 67506 108813 113933 133703 End 13990 158816 17240 35105 67505 108812 113932 133702 158816 Blocks 7050928+ 72992304 1637968+ 9003928+ 16329568+ 20818696+ 2580448+ 9964048+ 12657424+ Id 83 5 82 83 83 83 83 83 83 System Linux Esteso Linux swap / Solaris Linux Linux Linux Linux Linux Linux 50

Che cos'è una partizione? Il partizionamento è il mezzo per dividere un singolo hard disk in molti dischi logici. Una partizione è un insieme contiguo di blocchi su un disco che sono trattati come un disco indipendente. Una tabella delle partizioni è un indice che correla le sezioni dell'hard disk alle partizioni. Perché avere partizioni multiple? Incapsulare i dati. poiché la corruzione del file system è locale ad una partizione, se avviene qualche problema si perdono solo quelli della partizione. Incrementare l'efficienza dello spazio del disco. E' possibile formattare con differenti dimensioni dei blocchi, dipendente dal vostro utilizzo. Se i vostri dati consistono di un grande numero di piccoli file (meno di 1k) e la vostra partizione usa blocchi di 4k, state sprecando 3K per ogni file. In generale, si spreca in media la metà di un blocco per ogni file, così che adattando la dimensione del blocco alla dimensione media dei vostri file è molto importante se ne avete molti. Limitare la crescita dei dati. Processi incontrollabili oppure utenti maniacali possono consumare così tanto spazio su disco che il sistema operativo non ha più spazio sull'harddisk per le sue operazioni di salvataggio. Ciò condurrà a dei disastri. Dispositivi C'è una speciale nomenclatura che linux usa per riferirsi alle partizioni dell'hard disk. In Linux, le partizioni sono rappresentate da file di dispositivi. Questi sono dei falsi file che sono localizzati in /dev. Ecco alcuni esempi: brw-rw---brw-rw---crw------- 1 root 1 root 1 root disk disk tty 3, 8, 4, 0 May 0 May 64 May 5 5 5 1998 hda 1998 sda 1998 ttys0 Un file di dispositivo è un file di tipo c ( c sta per dispositivi a "carattere", dispositivi che non usano la memoria come cache) oppure b (per dispositivi a "blocchi", che usano la memoria cache. In Linux, tutti i dischi sono rappresentati solo come dispositivi a blocchi. 51

Nomi dei dispositivi Convezione sui nomi Per convenzione, i dischi IDE avranno nomi che variano da /dev/hda a /dev/hdd. L'hard disk A (/dev/hda) è il primo dispositivo e hard disk C (/dev/hdc) è il terzo. nome del controller del drive drive numero del drive /dev/hda 1 1 /dev/hdb 1 2 /dev/hdc 2 1 /dev/hdd 2 2 Tabella. Convenzione di denominazione dei controller IDE Un tipico PC ha due controller IDE, ognuno dei quali ha due dischi connessi ad esso. Per esempio /dev/hda è il primo drive (master) sul primo controller IDE e /dev/hdd è il secondo drive (slave) sul secondo controller (il quarto drive IDE nel computer). E' possibile scrivere direttamente su questi dispositivi (usando i comandi cat oppure dd). Comunque, poiché questi dispositivi rappresentano l'intero disco, con inizio nel primo blocco, si può erroneamente sovrascrivere il master boot record e la tabella delle partizioni, il che renderà inutilizzabile il drive. nome del drive controller del drive numero di drive tipo di partizione numero di partizione /dev/hda1 1 1 primary 1 /dev/hda2 1 1 primary 2 /dev/hda3 1 1 primary 3 /dev/hda4 1 1 swap NA /dev/hdb1 1 2 primary 1 /dev/hdb2 1 2 primary 2 /dev/hdb3 1 2 primary 3 /dev/hdb4 1 2 primary 4 Tabella. Nomi delle partizioni 52

Una volta che il drive è stato partizionato, le partizioni saranno rappresentate come numeri alla fine dei nomi. Per esempio, la seconda partizione sul secondo hard disk sarà /dev/hdb2. Il tipo di partizione (primary) è elencata nella tabella di sopra per chiarezza. nome del drive controller del tipo di numero di drive drive partizione numero di partizione /dev/sda1 1 6 primary 1 /dev/sda2 1 6 primary 2 /dev/sda3 1 6 primary 3 Tabella. Dischi SCSI I dischi SCSI seguono uno schema simile; sono rappresentati da 'sd' invece che da 'hd'. La prima partizione del secondo disco SCSI sarebbe perciò /dev/sdb1. Nella tabella precedente, il numero di drive è arbitrariamente scelto come numero 6 per introdurre l'idea che i numeri ID SCSI non si mappano sui nomi di dispositivi sotto Linux. Assegnazione dei nomi Sotto (Sun) Solaris e (SGI) IRIX, il nome del dispositivo assegnato ad un drive SCSI ha qualche relazione con dove lo inserite. Sotto Linux non è così e l'assegnazione è arbitraria. Prima SCSI ID #2 /dev/sda SCSI ID #5 /dev/sdb SCSI ID #7 /dev/sdc SCSI ID #8 /dev/sdd SCSI ID #7 /dev/sdb SCSI ID #8 /dev/sdc Dopo SCSI ID #2 /dev/sda I drive SCSI hanno numeri ID che variano da 1 a 15. Numeri ID SCSI più bassi sono assegnati a lettere di ordine più basso. Per esempio, se avete due dischi numerati 2 e 5, allora #2 sarà /dev/sda e #5 sarà /dev/sdb. Se li rimuovete entrambi, tutti i drive con numerazione più alta saranno ridenominati la prossima volta che si esegue il boot 53

Se avete due controller SCSI, bisogna esaminare l'output del comando /bin/dmesg allo scopo di vedere quale nome è stato assegnato ad ogni drive. Partizioni logiche nome del drive controller del drive numero di drive tipo di partizione numero di partizione /dev/hdb1 1 2 primary 1 /dev/hdb2 1 2 extended NA /dev/hdb5 1 2 logical 2 /dev/hdb6 1 2 logical 3 Tabella. Partizioni Logiche La tabella precedente illustra un misterioso salto nell'assegnazione dei nomi. Questo è dovuto all'utilizzo delle partizioni logiche. Numeri dei dispositivi La sola cosa importante con un file di dispositivo sono i suoi numeri di dispositivo major e minor, che vengono mostrati invece della dimensione dei file: $ ls -l /dev/hda brw rw 1 root disk permessi owner group 3, 0 numero major numero minor del dispositivo del dispositivo Jul 18 1994 /dev/hda data nome del dispositivo Tabella 6. Attributi dei file dispositivi Quando si accede ad un file di dispositivo, il numero major seleziona quale driver di dispositivo viene chiamato per l'esecuzione di operazioni di input/output. Questa chiamata viene fatta con il numero minor come parametro e sta interamente al dispositivo il modo in cui il numero minor viene interpretato. La documentazione del driver descrive usualmente come il driver usa i numeri minor. Per i dischi IDE disks, questa documentazione si trova in /usr/src/linux/documentation/ide.txt. Per i dischi SCSI ci si aspetterebbe che la documentazione si trovi in in 54

/usr/src/linux/documentation/scsi.txt, ma non si trova lì. Bisogna guardare al codice sorgente del driver per essere sicuro) ( /usr/src/linux/driver/scsi/sd.c:184-196). Fortunatamente, c'è la lista di Peter Anvin del numero dei dispositivi e dei nomi in /usr/src/linux/documentation/devices.txt. I numero major e minor sono ognuno un byte e questo è il motivo per cui il numero di partizioni per disco è limitato. Tipi di Partizione Una partizione è etichettata per ospitare un certo tipo di file system (da non confondere con una etichetta di volume). Tale file system potrebbe essere il file system standard ext2 oppure lo spazio di swap di linux swap, oppure file system stranieri come (Microsoft) NTFS o (Sun) UFS. Esiste un codice numerico associato ad ogni tipo di partizione. Per esempio, il codice per il tipo di partizione ext2 è 0x83 e lo swap di linux swap è 0x82. Per vedere una lista dei tipi di partizione ed i loro codici, bisogna eseguire il comando: /sbin/sfdisk -T IdNome 0 Vuoto Id 1 Nome FAT12 2 XENIX root 3 XENIX usr 4 FAT16 <32M 5 Esteso 6 FAT16 7 HPFS/NTFS 8 AIX 9 AIX avviabile a OS/2 Boot Manager b W95 FAT32 c W95 FAT32 (LBA) e W95 FAT16 (LBA) f W95 Esteso (LBA) 10 OPUS 11 FAT12 nascosto 12 Diagnostica Compaq 14 FAT16 nascosto <32M 16 FAT16 nascosto 17 HPFS/NTFS nascosto 18 AST SmartSleep 1b W95 FAT32 nascosto 1c W95 FAT32 (LBA) nascosto 1e W95 FAT16 (LBA) nascosto 24 NEC DOS 39 Plan 9 3c Recupero PartitionMagic 55

40Venix 80286 41 PPC PReP Boot 42SFS 4d QNX4.x 4eQNX4.x 2a partiz. 4f QNX4.x 3rd partiz. 50OnTrack DM 51 OnTrack DM6 Aux1 52 CP/M 53 OnTrack DM6 Aux3 55 EZ-Drive 56 Golden Bow 54 OnTrackDM6 5c Priam Edisk 61 SpeedStor 63 GNU HURD o SysV 64Novell Netware 286 65 Novell Netware 386 70 DiskSecure Multi-Boot 75 PC/IX 80 Vecchio Minix 81 Minix / vecchio Linux 82 Linux swap / Solaris 83 Linux 84 C nascosto OS/2: drive 85 Linux esteso 86 set volume NTFS 87 set volume NTFS 88 Linux plaintext 8e Linux LVM 93 Amoeba 94 Amoeba BBT 9f BSD/OS a0 Ibernazione IBM Thinkpad a5 FreeBSD a6 OpenBSD a7 NeXTSTEP a8 Darwin UFS a9 NetBSD ab Darwin boot b7 BSDI fs b8 BSDI swap bb Boot Wizard hidden be Solaris boot bf Solaris c1 DRDOS/sec (FAT-12) c4 DRDOS/sec (FAT-16 < 32M) c6 DRDOS/sec (FAT-16) c7 Syrinx da Non-FS data db CP/M / CTOS /... de Dell Utility df BootIt e1 accesso DOS e3 DOS R/O e4 SpeedStor eb BeOS fs ee EFI GPT 56

efefi (FAT-12/16/32) f2 DOS secondario f0linux/pa-risc boot f1 SpeedStor f4speedstor fd Autorilevamento raid di Linux felanstep ff BBT Tipi di partizioni straniere I codici del tipo di partizione sono state scelte arbitrariamente e sono particolari di un dato sistema operativo. Perciò, è teoricamente possibile che se usate due sistemi operativi con lo stesso hard disk, lo stesso codice potrebbe essere usato per designare due differenti tipi di partizione. OS/2 marca le sue partizioni con il tipo 0x07 così come fa NTFS di Windows NT. MS-DOS alloca parecchi tipi di codice per i suoi vari tipi di file system FAT: 0x01, 0x04 e 0x06 sono noti. DR-DOS usava 0x81 per indicare partizioni FAT protette, creando a suo tempo una interferenza di tipo con Linux/Minix, ma né Linux/Minix né DR-DOS sono più così ampiamente usati. Partizioni primarie Il numero di partizioni su un sistema Intel-based fu limitato dai primissimi tempi: l'originale tabella delle partizioni fu installata come parte del settore di boot e conteneva spazio solo per quattro nomi di partizioni. Queste partizioni ora vengono chiamate partizioni primarie. Partizioni logiche Una partizione primaria dii un hard drive può essere sub-partizionato. Queste si chiamano partizioni logiche. Questo ci consente effettivamente di superare la classica limitazione delle quattro partizioni. La partizione primaria utilizzata per contenere le partizioni logiche viene chiamata partizione estesa ed ha il proprio tipo di file system (0x05). Diversamente dalle partizioni primarie, le partizioni logiche devono essere contigue. Ogni partizione logica contiene un puntatore alla successiva partizione logica, il che implica che il numero di partizioni logiche è illimitato. Comunque Linux impone limiti sul numero totale di ogni tipo di partizioni su un drive, così questo limita effettivamente il numero di partizioni logiche. Questo è al più 15 partizioni totali su un disco SCSI ed un totale di 63 su un disco IDE. Partizioni di Swap Per ogni processo in esecuzione sul computer viene allocato un numero di blocchi di RAM. Questi 57

blocchi vengono chiamati pagine. L'insieme di pagine in memoria che saranno referenziata da processore nell'immediato futuro viene chiamato working set." Linux cerca di predire questi accessi alla memoria (presumendo che le pagine recentemente utilizzate saranno usate nell'immediato futuro) e le mantiene in RAM se possibile. Se si hanno troppi processi in esecuzione su un computer, il kernel cercherà di liberare la RAM scrivendo le pagine su disco. Questo è lo scopo per cui viene usato lo spazio di swap. Ciò incrementa effettivamente la quantità di memoria a disposizione. Comunque, l'i/o su disco è cento volte più lento della lettura dalla RAM. Consideriamo lo swap come memoria di emergenza e non come memoria extra. Se la memoria diventa così scarsa che il kernel libera il working set di un processo allo scopo di caricarne un'altro, si dice che la macchina sta liberando la spazzatura. Lo spazio di swap è qualcosa che bisogna avere ma non è un sostituto per RAM insufficiente. 58

Come si presenta un filesystem Linux Il filesystem di Linux si presenta come una gerarchia unificata che inizia dalla directory (/) radice e si dirama in diversi file e sottodirectory seguendo una struttura ad albero. Ci sono molte differenze tra il filesystem di Windows (e DOS ovviamente) e quello del nostro Linux, la più importante, e visibile, è questa: Windows assegna ad ogni partizione o periferica di memorizzazione (floppy e cdrom) una unità separata (quindi un filesystem a se), Linux invece ha una sola unità (la /) dove verranno montate tutte le partizioni e le periferiche di memorizzazione Questo approccio porta il vantaggio di una maggiore velocità di navigazione (del filesystem ovviamente) grazie alla centralizzazione (non più a:, c:, d: e:, ma solo /, /mnt/cdrom, /mnt/floppy, ecc) 59

Albero delle directory e filesystem Sebbene il filesystem sia concepibile come un insieme ordinato di file raggruppati in diverse directory e sottodirectory, non va confuso con l'albero delle directory di un sistema Linux. Albero delle directory L'albero delle directory di un sistema Linux costituisce l'insieme complessivo dei file e delle directory su cui si sviluppa un intero sistema Linux e può essere (e spesso lo è) formato da più filesystem. A differenza di un sistema Windows una installazione di un sistema Linux può essere distribuita su più partizioni di uno stesso disco o addirittura su più dischi. Ciò comporta che l'albero complessivo delle directory sia formato da più file system. Possiamo pensare al file system come ad un blocco o ad un ramo dell'albero delle directory, il cui contenuto è fisicamente situato in uno specifico dispositivo di memorizzazione, che può essere: la partizione di un hard disk un floppy un cd-rom la stessa memoria RAM. Unire più file system: il mounting Il meccanismo che permette ad un sistema Linux di legare più file system in un unico albero di directory si chiama mounting. Il mounting permette di agganciare un file system ad una directory di un altro filesystem. In tal modo il contenuto del filesystem montato sarà visibile a partire dalla directory su cui è stato montato. Quest'ultima directory viene chiamata punto di mounting. 60

Un tipico esempio di tale operazione, è quando si vuole accedere ad un dispositivo esterno come un cdrom o un floppy. I dati presenti in un cdrom o in un floppy sono essi stessi organizzati in un file system. Per poterli visualizzare in un sistema Linux occorrerà preliminarmente montare il loro file di dispositivo su un determinato punto di mount e quindi entrare in tale directory. 61

Punti di mount L'unica partizione alla quale si avrà accesso dopo il boot è la partizione di root che è quella dalla quale, quasi sempre, è stato eseguito il boot. La partizione di root conterrà la directory root del file system, il nodo principale dal quale si diparte ogni altra cosa. Le altre partizioni del file system devono essere attaccate a tale partizione, affinché l'intero file system a partizioni multiple sia accessibile. Durante il processo di boot, il sistema renderà accessibili queste partizioni non-root. FILESYSTEM E PARTIZIONI Durante l'installazione di Linux viene richiesto come partizionare i(l) propri(o) hard disk, in modo da definire cosa formattare e dove installare il sistema operativo, se preservare le eventuali partizioni esistenti (contenenti altri OS) o ripulire completamente gli hard disk. Diskdruid e Fdisk Gli strumenti generalmente disponibili per questa operazione sono: fdisk Tool testuale con la possibilità di operazioni avanzate per il partizionamento diskdruid Tool grafico fornito da RedHat, semplice ed intuitivo alternativa funzionale a fdisk se non si hanno bisogno di funzionalità avanzate Con diskdruid e fdisk si ha la possibilità di decidere come partizionare i propri hard disk e decidere quale filesystem adottare per far girare linux. Il minimo partizionamento richiesto prevede: - una partizione generale (/, root) in cui saranno inseriti tutti i file. - una partizione di swap (usata come Virtual Memory) E' preferibile, nelle installazioni standard avere un miglior partizionamento cioè dedicare partizioni indipendenti per: - / (la root, sotto la quale stanno tutte le altri directory 62

- /boot (partizione di boot, dove risiede kernel e file di boot. 20 Mb di spazio possono bastare) - /var (partizione in cui vengono messi file che cambiano di dimensione, tipicamente i log. E' utile averla su partizione indipendente per evitare che un aumento dei log inattesi riempa tutto il filesystem. Farla almeno di 100 Mb) - /home (dove risiedono i file di tutti gli utenti. Può essere piccola e praticamente inutilizzata (mail, dns server) o molto grossa e piena di documenti (web, file server) - /tmp dove risiedono file temporanei. In fase di partizionamento, oltre a decidere come partizionare gli hard disk bisogna assegnare ad ogni partizione un mount point. Per esempio se abbiamo un hard disk da 10 Gb come primary master e lo vogliamo dividere in 6 partizioni, potremo ottenere: Partizione Mount Point Partizione Mount Point Partizione Mount Point /dev/hda1 / /boot /dev/hda3 /var /dev/hda4 /home /dev/hda5 /dev/hda6 SWAP /dev/hda2 /tmp Considerare inoltre che possiamo formattare ogni partizione con un file system diverso. Possiamo per esempio avere, nell'esempio sopra, tutte le partizioni in ext2 (File System nativo di Linux) e la partizione /dev/hda4 (dove viene montata la /home) formattata in FAT 32 (File System di Windows 98, supportato anche da Linux). Le principali directory La directory / È la directory radice ed oltre a contenere tutte le altre directory può contenere anche l'immagine del kernel (non sempre, alcune volte la troviamo in /boot). La directory /bin Assieme a /sbin è la directory basilare di ogni sistema Linux poiché contiene le utilità di base per 63

il funzionamento del sistema. La directory /dev Contiene tutti i dispositivi, file speciali che sono associati alle periferiche (cioè ai loro indirizzi di I/O, IRQ e DMA) dal kernel. La directory /etc Contiene tutti i file di configurazione (in semplice formato ASCII, quindi modificabili con un semplice editor di testo. Nella directory rc.d troviamo i file di init indispensabili per il corretto boot della macchina Linux. La directory /lib Contiene le librerie condivise usate dai programmi durante la loro esecuzione. La directory /lost+found Contiene file persi o corrotti dopo il loro recupero. La directory /mnt Directory utilizzata di solito come punto di mount delle periferiche di memorizzazione. La directory /opt In alcune distribuzioni contiene applicazioni particolari (di solito KDE, GNOME, OpenOffice e similari). La directory /proc È una directory virtuale creata dal sistema operativo (dal kernel in primis) e contiene dati relativi ai processi in corso e alle caratteristiche della macchina. La directory /tmp Contiene tutti i file temporanei necessari alle diverse applicazioni durante la loro esecuzione. Questa directory puo' essere svuotata in ogni momento (alcuni processi in esecuzione potrebbero avere dei problemi dopo lo svuotamento della tmp). La directory /usr 64

Contiene tutte le applicazioni non basilari per l'utente normale (/usr/bin), per l'amministratore (/usr/sbin), e le loro librerie (/usr/lib). In /usr/local troviamo (per default) tutte le applicazioni inserite dopo l'installazione. In /usr/src troviamo i sorgenti delle applicazioni compresi quelli del kernel (/usr/src/linux). La directory /var Contiene i dati variabili come posta elettronica, code di stampa, log, ecc. Comandi di gestione del File System Prima di poter utilizzare un filesystem (es: CDROM, floppy, tape, condivisione di rete windows, directory nfs, partizione fat32 di un hard disk... ) questo deve essere formattato e montato in una subdirectory della root ( / ). Una volta montato il filesystem risulta accessibile a programmi e utenti in modo trasparente e diventa parte integrante dell'albero delle directory sotto / Dopo l'uso il filesystem può essere smontato (operazione necessaria per espellere un CDROM o un floppy). La directory su cui viene montato un filesystem può anche non essere vuota, ma nel momento in cui ci viene montato un file system, i dati ivi contenuti non sono più visibili fino a quando non si smonta il file system. Il comando per montare un dispositivo a blocchi su un file system ha la sintassi seguente: mount -t [tipo fs] [opzioni] device dir tipo fs indica il tipo di file system device indica il dispositivo dir indica il punto di mount Il comando per montare un cd rom è il seguente: 65

mount /dev/cdrom Il comando per montare un floppy è il seguente: mount /dev/fd0 66

Il file /etc/fstab Nel file /etc/fstab vengono configurate le informazioni sui vari file system (da montare al boot o no) preimpostati sul sistema, vengono definiti i mount point, il tipo di file system ed altre informazioni. Il suo formato prevede per ogni riga le seguenti informazioni: 1- Dispositivo da montare (es: /dev/hda1) 2- Mount point sul file system principale 3- File System Type da utilizzare (es: ext2, ext3, iso9660, nfs...) 4- Opzioni specifiche per il mount 5- Indica se il file system deve essere backuppato con il comando dump. Uno 0 indica NO. 6- Indica de deve essere fatto un file system check al boot. Uno 0 indica NESSUN CHECK. Il file /etc/mtab Il file /etc/mtab mostra le informazioni relative ai file system in uso sul sistema. Viene modificato dinamicamente quando nuovi file system vengono montati. Esempio. Diamo da shell il comando more /etc/mtab [padrone@www ~]$ more /etc/mtab /dev/hda1 / ext3 rw 0 0 none /proc proc rw 0 0 none /sys sysfs rw 0 0 none /proc/bus/usb usbfs rw,devmode=0664,devgid=43 0 0 /dev/hda8 /home ext3 rw 0 0 /dev/sda8 /mnt/linux2 ext3 rw 0 0 /dev/sda2 /mnt/dati ext3 rw 0 0 none /mnt/floppy supermount rw,sync,dev=/dev/fd0,fs=ext2:vfat,-- 0 0 /dev/sda7 /mnt/linux ext3 rw 0 0 /dev/sda5 /mnt/multimedia ext3 rw 0 0 /dev/sda1 /mnt/windows ext3 rw 0 0 /dev/hda11 /mnt/windows2 ext2 rw 0 0 /dev/sda6 /mnt/windows3 ext3 rw 0 0 67

/dev/hda9 /tmp ext3 rw 0 0 /dev/hda6 /usr ext3 rw 0 0 /dev/hda7 /var ext3 rw 0 0 /dev/hda10 /var/www ext3 rw 0 0 sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw 0 0 nfsd /proc/fs/nfsd nfsd rw 0 0 /dev/sdb1 /mnt/kingston vfat rw,nosuid,nodev,noatime,codepage=850,iocharset=iso885915,user=padrone 0 0 Smontare un dispositivo Il comando per smontare un dispositivo a blocchi su un file system ha la sintassi seguente: umount [ opzioni ] device 68

I file Un file è una collezione di informazioni, al quale viene dato un nome, filename. Esempi di file potrebbero essere i sorgenti dei programmi in C, i fogli di calcolo, le relazioni, le immagini, ecc. I file vengono identificati dai loro filename, ma non c'è una regola per la formazione di tali nomi: in generale, i filename possono contenere qualsiasi carattere (eccetto il carattere / ) e sono limitati a 256 caratteri di lunghezza. 69

Le directory Una directory è una collezione di file. Possiamo pensare ad una directory come ad una cartella che contiene differenti file. Alle directory stesse si dà un nome, con le quali le identificheremo. Inoltre, le directory sono gestite in una struttura ad albero: cioè, le directory possono contenere altre directory. Possiamo riferirci ad un file tramite il suo pathname, che è costituito dal nome del file, preceduto dal nome della directory contenente il file. Per esempio, supponiamo che uno studente, john, abbia una directory chiamata relazioni, che contiene tre file: relcalcolo1.doc, informatica1.doc, informatica2.doc. Per riferirci al file informatica1.doc, possiamo specificare il suo pathname: relazioni/informatica1.doc Le directory possono essere innestate l'una dentro l'altra. Ad esempio, supponiamo che john abbia una directory calcolo all'interno della directory relazione. E questa directory contenga il file relcalcolo.doc. Il pathname di relcalcolo1.doc sarà: relazioni/calcolo/relcalcolo1.doc Possiamo vedere il pathname come un percorso da prendere per localizzare un certo file. La directory che si trova al di sopra di una data directory si chiama directory genitore (parent directory). Nel nostro caso, la directory relazioni è la directory genitore della directory calcolo. La struttura ad albero delle directory Molti sistemi UNIX hanno uno schema standard per la gestione dei file, in modo tale che le risorse del sistema ed i programmi possono essere facilmente localizzate. Questo schema forma un albero 70

di directory, che inizia dalla directory /, conosciuta anche come la directory radice (root directory). Direttamente al di sotto della root directory / ci sono alcune sottodirectory importanti: /bin, /etc, /dev e /usr. Queste directory a loro volta contengono altre directory che contengono i file di configurazione del sistema, programmi, e così via. Figura 1 Una tipica directory ad albero di Linux/Unix La directory di lavoro corrente In qualsiasi momento, i comandi che digitiamo nella shell sono dati in termini della directory corrente di lavoro. Si può pensare della directory corrente come alla directory nella quale si è posizionati quando si sta lavorando. Quando si accede al sistema da login, la directory di lavoro 71

viene impostata alla vostra home directory, ad esempio, home/studenti/3h. Ogni volta che ci si riferisce ad un file, si può fare riferimento ad esso in relazione alla directory corrente di lavoro, invece di specificare il pathname completo del file. Esempio: se vogliamo visualizzare il file relcalcolo1.doc, possiamo usare il comando more /home/studenti/3h/calcolo/relcalcolo1.doc Il comando more visualizza semplicemente un file, una schermata alla volta. Ad ogni modo, poiché la nostra home directory è /home/studenti/3h, possiamo riferirci al file relativo alla directory corrente more /calcolo/relcalcolo1.doc Se iniziamo il nome di file con il carattere / (come in calcolo/relcalcolo1.doc) con un carattere diverso da /, il sistema suppone che ci si riferisca al file in termini relativi alla directory corrente di lavoro. Ciò si dice pathname relativo. Se invece iniziamo un nome di file con il carattere /, il sistema interpreta ciò come un pathname completo cioè, un pathname che include il percorso completo al file, a cominciare dalla directory root, e cioè / (root directory). Parliamo allora di pathname assoluto. Fare riferimento alla directory home Sia sotto tcsh chw bash9, ci si può riferire alla home directory usando il carattere tilde10 ( ~ ). Ad esempio, il comando: more ~/calcolo/relcalcolo1.doc è equivalente a more /home/studenti/3h/calcolo/relcalcolo1.doc Il carattere ~ viene semplicemente sostituito dalla shell con il nome della home directory dell'utente. Inoltre, sempre con il carattere ~ si può specificare la home directory di altri utenti. Ad esempio, il pathname ~3i/italiano viene tradotto in home/studenti/3i/italiano. 9 10 Tcsh e bash sono due shell usate in Linux. Una shell è il programma che legge i comandi dell'utente e li esegue. Il carattere tilde ( ~ ) si digita usando la combinazione di tasti AltGr + ì 72

Primi passi in Linux Prima di iniziare, è importante notare che tutti i nomi di file e comandi su un sistema UNIX sono case-sensitive. Ad esempio, il comando ls è diverso dal comando LS. Lo stesso vale per i nomi di directory. Spostarsi tra le directory Il comando per spostarsi tra le directory é cd, una abbreviazione per change directory. L'uso del comando cd è il seguente cd <directory> dove <directory> è il nome della directory sulla quale vogliamo posizionarci. Abbiamo detto che dopo il login (la fase di accesso al computer), siamo automaticamente posizionati nella home directory personale. Ad esempio, l'utente francesco, dopo il login si ritrova nella sua home personale /home/francesco Se volesse spostarsi nella sottodirectory laboratorio, dovrebbe usare il comando cd laboratorio e si troverebbe quindi posizionato nella directory /home/francesco/laboratorio Per tornare indietro alla directory genitore (quella che si trova ad un livello immediatamente superiore alla directory corrente), si usa il comando: cd.. Notate lo spazio tra cd e.. Ogni directory ha un elemento speciale chiamato.., che si riferisce alla sua directory genitore. Allo stesso modo, ogni directory ha un elemento 73

chiamato. che si riferisce alla directory stessa. Quindi il comando cd. non porta da nessuna parte. Per spostarsi tra le directory è anche possibile usare i pathname assoluti. Ad esempio, trovandosi nella directory /home/francesco/laboratorio e volendosi spostare nella directory home dell'utente 3h, scriviamo cd /home/studenti/3h Il comando cd senza argomenti riporta l'utente alla directory home personale Es. l'utente docente si trova in /home/francesco/laboratorio. Per spostarsi subito alla sua directory home, scriverà: cd e si troverà subito sulla directory /home/docente Visualizzare il contenuto delle directory Il comando ls visualizza un elenco dei file e delle directory, per default a partire dalla directory home dell'utente. Per esempio, supponiamo di trovarci nella home directory dell'utente francesco: /home/francesco il comando ls elencherà tutti i file e tutte le cartelle: 74

VOTI_LAB_CALCOLO.xls* corso_computer.doc fortran_source/ libri_programmazione.txt Linux_base/ liste_dinamiche.pdf matematica/ Programmazione_Linux/ software_linux/ tutorial fortran/ tutorial_programmazione_c/ Possiamo vedere che l'utente francesco ha 10 elementi nella sua home directory, di cui 7 directory e 3 file. Come facciamo a distinguere una directory da un file? Semplice! Ad ogni directory viene aggiunto il carattere / alla fine. Quindi: fortran_source/ Linux_base/ matematica/ Programmazione_Linux/ software_linux/ tutorial fortran/ tutorial_programmazione_c/ sono directory, mentre VOTI_LAB_CALCOLO.xls* corso_computer.doc libri_programmazione.txt liste_dinamiche.pdf sono semplici file. Un asterisco alla fine del file indica che questo è un file eseguibile, o un programma che può essere eseguito. In generale, qualsiasi comando UNIX può prendere un numero qualsiasi di opzioni ai aggiunta ai suoi argomenti. Tali opzioni di solito iniziano con un -. Ad esempio, l'opzione -F dice al comando ls di fornire maggiori informazioni sul tipo dei file. Se forniamo al comando ls il nome di una directory, ls visualizzerà il contenuto di tale directory. Es. il comando ls software_linux -F visualizzerà l'elenco di file e directory presenti nella directory software_linux 75

avidemux-0.9-0.dag.rh80.i386.rpm bgi_library.tar.gz binary.tar celestia-kde-textures-1.3.2-3mdk.i586.rpm* cheops-0.61/ eclipse/ fpc-1.0.10.i386.tar gambas-0.99.rc4-1rk.src.rpm* gtk+-2.6.2.tar.gz libsql.0.46.zip mozilla-i686-pc-linux-gnu-1.7.5-installer.tar.gz Xfree86-4.4.0-src-1.tgz* Per esercizio, provate a spostarvi tra le directory, usando i comandi cd e ls. Creazione di nuove directory Per creare una nuova directory usiamo il comando mkdir. Ad esempio, il comando mkdir relazioni crea una nuova directory all'interno della directory corrente di lavoro. Spostiamoci sulla directory home con il comando cd: cd Creiamo una nuova directory, italia, con il comando mkdir mkdir italia Il comando ls visualizza la directory creata. Diamo il comando ls: ls Ed ecco il risultato italia/ Il carattere / ci conferma che italia è una directory. Ora spostiamoci all'interno della nuova directory creata: cd italia All'interno di tale directory creiamo tante nuove directory quante sono le regioni italiane. Di seguito sono elencati i comandi da dare per creare le 20 directory: 76

mkdir campania mkdir basilicata mkdir calabria mkdir puglia mkdir sicilia mkdir sardegna mkdir lazio mkdir mkdir mkdir mkdir mkdir mkdir mkdir liguria piemonte trentino-alto-adige friuli-venezia-giulia lombardia toscana abruzzo mkdir mkdir mkdir mkdir mkdir mkdir molise emilia-romagna veneto valle-aosta marche umbria Per vedere se le directory sono state create, dia un comando ls: ls Ed ecco il risultato abruzzo/ basilicata/ calabria/ campania/ emiliaromagna/ friuliveneziagiulia/ lazio/ liguria/ lombardia/ marche/ molise/ piemonte/ puglia/ sardegna/ sicilia/ toscana/ trentino-altoadige/ umbria/ valle-aosta/ veneto Esercizio Scelta una regione a piacere, creare all'interno della rispettiva directory tante sottodirectory quante sono le sue province. Ad esempio, per la campania, dobbiamo creare 5 sottodirectory, avellino, benevento, caserta, napoli, salerno. Copiare i file: il comando cp Ora impariamo come copiare un file da una posizione all'altra. Per copiare i file si usa il comando cp. Il comando cp richiede due argomenti aggiuntivi, cioè il file da copiare, e la posizione nel quale copiare il file. cp sorgente destinazione sorgente è il pathname del file da copiare, destinazione è il pathname sul quale il file sorgente sarà copiato. Ad esempio, supponiamo di avere nella cartella /home/francesco/rel il file 77

relcalcolo1.doc, e di voler ricopiare tale file sempre nella stessa cartella, ma con un nuovo nome di relcalcolo2.doc. La prima cosa da fare (la più semplice) è posizionarsi all'interno della cartella dove è presente il file da copiare: cd /home/francesco/rel scriviamo poi: cp relcalcolo1.doc relcalcolo2.doc Se il file relcalcolo2.doc è presente, sarà richiesto se vogliamo sovrascriverlo. Se invece vogliamo copiare il file relcalcolo2.doc nella sottodirectory matematica, scriviamo: cp relcalcolo2.doc /home/francesco/matematica/relcalcolo2.doc Possiamo anche scrivere cp relcalcolo2.doc /home/francesco/matematica senza specificare il nome del file. Poiché ci troviamo nella cartella /home/francesco/rel, possiamo anche scrivere: cp relcalcolo2.doc../matematica/relcalcolo2.doc perché le directory matematica e relazioni sono entrambe figlie della directory genitore francesco. Possiamo anche specificare il pathname assoluto per specificare la sorgente e la destinazione: cp /home/francesco/rel/relcalcolo1.doc/home/francesco/matematica/relcalcolo2.doc Per copiare un file sulla directory corrente possiamo scrivere cp /home/francesco/matematica/relcalcolo2.doc. Il carattere. significa la directory corrente. E' solo un modo speciale per indicare la directory corrente. Spostare i file: il comando mv Il comando mv sposta i file, invece di copiarli. La sintassi del comando è molto semplice: mv sorgente destinazione dove sorgente e destinazione sono rispettivamente il file da spostare ed il file/directory sul quale spostare la sorgente. Ad esempio, il comando: mv relcalcolo1.doc /home/francesco/matematica/ 78

sposta il file relcalcolo1.doc nella sottodirectory matematica. Il comando mv relcalcolo1.doc /home/francesco/matematica/relcalcolo2.doc sposta il file relcalcolo1.doc nella sottodirectory matematica cambiando però anche il nome del file. Alla fine il file relcalcolo1.doc non esisterà più. Questa è la differenza11 con il comando cp, che duplica i file. Il comando mv può anche servire per spostare intere directory. Ad esempio, supponiamo di voler spostare la directory italia nella directory italia2 Scriviamo: mv italia/ italia2/ Ovviamente la directory italia si trova nella directory corrente, così come la directory italia2 che sarà creata al posto della directory italia. 11 I comandi cp e mv sostituiranno il file di destinazione (se già esiste) senza chiederlo. State attenti quando copiate un file in un'altra directory: potrebbe esserci già un file con lo stesso nome in quella directory, che sarebbe sovrascritto. 79

Il comando man In ogni installazione di UNIX è presente un sistema di help molto corposo sotto forma di manuali (comando man). La pagine dei manuali documentano molti aspetti del vostro sistema, come programmi specifici, comandi, utilità e concetti relativi a Unix. Se volete fare una prova date il comando "man man" e vi apparirà il manuale del comando man. man mostra la guida in linea relativa al comando con qui e' stato richiamato man. es: man ls Questo comando mostra l'help in linea relativa al comando ls. Il manuale in linea è un insieme di files memorizzati su disco, ognuno dei quali contiene la documentazione relativa ad un argomento o ad un comando UNIX. Per accedere al manuale si utilizza il comando man seguito dal nome del comando su cui si vogliono avere informazioni. Per avere informazioni riguardo al comando man si digita man man Il manuale è diviso in 8 sezioni principali : Alcune sezioni sono divise in sottosezioni: la Sezione 1, ad esempio, è sempre il riferimento principale per i comandi, ma si possono vedere la Sezione 1c, per i comandi di comunicazione, la 1g per i comandi grafici, la 1X, per i comandi X Window, e così via. 80

Per orientarsi nelle diverse parti del manuale, ogni sezione e sottosezione contiene una pagina chiamata intro che fornisce una breve introduzione. Un buon modo per familiarizzare con i contenuti di una sezione è visualizzare la sua pagina intro. All'interno di una sezione, il singolo pezzo di documentazione è chiamato pagina o voce. Per comodità, ogni pagina del manuale è organizzata secondo un formato predefinito che utilizza le intestazioni mostrate nella tabella sottostante. Non tutte le pagine del manuale avranno tutte le intestazioni e, inoltre, alcuni sistemi Unix utilizzano intestazioni diverse; tuttavia, se si comprendono quelle standard, sarà più facile capire lo schema utilizzato dal vostro sistema. Le intestazioni standard utilizzate dal Manuale Unix in linea Name nome e scopo del comando Synopsis sintassi del comando Description descrizione completa (può' essere lunga) Files lista dei file importanti per il comando See also dove cercare informazioni correlate Diagnostics possibili errori e avvertimenti Bugs errori, difetti e avvertimenti Quando si utilizza il comando man di base, Unix visualizza l' intera pagina del manuale. descrizione. Tuttavia, a volte si è interessati solo a una breve La sezione Name di ogni pagina contiene una descrizione di una linea. Se ciò che interessa è questa descrizione breve, si deve utilizzare il comando man seguito dall'opzione -f e dal nome di uno o più comandi. Per comodità, è possibile utilizzare la singola parola whatis, invece di man -f. Utilizzando il comando man regolare, è possibile specificare un numero di sezione. Con man -f o whatis, ciò non è permesso e Unix effettuerà sempre la ricerca in tutto il manuale. Affinché whatis lavori correttamente, le pagine del manuale devono essere pre-elaborate in un certo modo: tutte le descrizioni brevi sono raccolte e memorizzate in specifici file ed è in questi che whatis effettua la ricerca, non nel manuale vero. 81

Se la pre-elaborazione non è stata effettuata, il comando whatis non è in grado di restituire informazioni utili. Nel caso in cui si sappia cosa si vuole fare, ma non si abbia la sicurezza del comando da utilizzare, è possibile utilizzare man con l' opzione -k, per cercare i comandi nella cui descrizione compaiano determinate parole chiave. Quando si utilizza questa opzione, Unix controlla tutte le descrizioni brevi dei comandi, cercando e visualizzando tutte quelle che contengono la stringa di caratteri che è stata specificata. Per comodità, in alternativa a man -k, è possibile utilizzare il comando apropos. È poi necessario ricordare che nella ricerca delle stringhe specificate, Unix non distingue tra lettere minuscole e lettere maiuscole. 82

Le variabili di Shell e l'ambiente Linux La Shell permette di definire delle variabili così come fanno i linguaggi di programmazione. Una variabile è un dato al quale viene dato un nome. Quando si assegna un valore ad una variabile (usando l'operatore = ), si può accedere alla variabile anteponendo al suo nome il carattere $. Esempio: definiamo la variabile prova prova= ciao a tutti alla variabile prova viene assegnato il valore ciao a tutti. Possiamo riferirci a questo valore tramite il nome della variabile preceduto dal carattere $. Il comando echo $prova visualizza il contenuto della variabile prova. Queste variabili sono interne alla shell. Ciò significa che solo la shell può accedere a questi valori. Usando il comando set si potrà visualizzare la lista di tutte le variabili di shell che sono state definite. Comunque la shell permette di esportare le variabili in tutto l'ambiente. L'ambiente è l'insieme delle variabili ai quali tutti i comandi possono accedere. Una volta definita una variabile al interno di una shell, esportandola rende questa variabile parte dell'ambiente. Il comando export viene usato per esportare una variabile nell'ambiente. L'ambiente è molto importante nel sistema operativo Unix. Esso permette di configurare certi comandi importando certe variabili conosciute ai comandi. Ad esempio, la variabile di ambiente PAGER viene usata dal comando man. Tale variabile specifica al comando da usare di visualizzare le pagine del manuale una schermata alla volta. Impostiamo la variabile PAGER a cat PAGER= cat Ciò farà in modo che l'output del comando man venga visualizzato sullo schermo tutto in una sola volta, senza dividerlo in pagine. Ora, esportiamo la variabile PAGER all'ambiente: export PAGER 83

Proviamo il comando man ls Le pagine del manuale per l'istruzione ls dovrebbero scorrere velocemente sullo schermo senza nessuna pausa. Ora, se impostiamo PAGER a more, sarà usato il comando more per visualizzare le pagine del manuale. PAGER= more Si noti che non dobbiamo più usare il comando export dopo che il valore di PAGER è stato cambiato. Bisogna esportare una variabile solo una volta; qualsiasi cambiamento fatto alla variabile da quel momento in poi sarà automaticamente propagata all'ambiente. L'ambiente è usato anche per mantenere traccia di importanti informazioni relative alla sessione di login. Ad esempio la variabile ambientale HOME, che contiene il nome della home directory dell'utente connesso. Il comando echo $HOME visualizzerà allora il nome della home directory dell'utente connesso: Un'altra interessante variabile ambientale è PS1, che definisce il prompt della shell principale. Ad esempio, il comando echo $PS1 visualizzerà il prompt corrente. Il prompt è il messaggio che compare nella shell prima del cursore lampeggiante. Se scriviamo PS1= Inserite il vostro comando: vediamo che succede: 84

85

86

Prompt di comando Ecco che il prompt è cambiato. Prima del cursore lampeggiante è comparsa la frase Inserire il vostro comando Esercizio come facciamo a preservare il contenuto del vecchio prompt, e ripristinarlo dopo le nostre prove? Semplice, usiamo una nuova variabile di ambiente, che chiamiamo oldps1, nella quale memorizziamo il valore corrente di PS1: oldps1=$ps1 a questo punto possiamo modificare PS1: PS1= Ai suoi ordini padrone e ripristinare in seguito il vecchio valore di PS1, con l'assegnazione PS1=$oldPS1 Non dimentichiamo di far precedere alla variabile oldps1 Il carattere $, altrimenti assegneremo alla variabile di ambiente PS1 un valore nullo, in quanto, per riferirci al contenuto di oldps1 dobbiamo usare la notazione $oldps1. 87

Dopo aver cambiato il prompt, possiamo ripristinarlo senza problemi. 88

Vediamo cosa succede se invece di scrivere PS1=$oldPS1, scriviamo PS1=oldPS1 Come si vede, a PS1 non viene assegnato il valore contenuto in oldps1, ma la stringa oldps1 E' importante ricordare che la stringa PS1 viene memorizzata nell'ambiente come qualsiasi altra variabile ambientale. Se la modifichiamo a riga di comando, il prompt cambierà. Quindi, prima di fare qualsiasi cambiamento, salviamo il prompt corrente in un'altra variabile ambientale: SAVE=$PS1 Il prompt più semplice è il singolo carattere. Vediamo cosa succede se scriviamo PS1=$ 89

Ecco che il prompt, che prima era la stringa bash-3.00$ si è trasformato nel singolo carattere $ Sappiamo come ripristinarlo: scriviamo PS1=$SAVE Ci sono comunque tante possibilità di personalizzare il prompt della shell. Ad esempio, è possibile visualizzare ogni volta la data, all'interno del prompt. Basta usare una sequenza di caratteri speciale, cioè \d Proviamo a scrivere PS1= \d dopo aver salvato il valore corrente di PS1 con SAVE=$PS1 La stringa formata da un carattere preceduto dal carattere \ si chiama sequenza di escape. Allora, la sequenza di escape \d permette di modificare il prompt, visualizzando la data corrente, nel formato: 90

Giorno della settimana, mese, giorno del mese La sequenza di escape \a La sequenza di escape \H produce un ASCII bell character (07) visualizza il nome del computer 91

La variabile ambientale SHELL Per verificare se stiamo usando la shell denominata Bourne Shell, usiamo la variabile d'ambiente SHELL, che contiene il nome della shell usata dall'utente: quindi, se scriviamo echo $SHELL dovrebbe essere visualizzato /bin/sh. Se viene visualizzato /bin/csh, stiamo eseguendo una C shell. Se invece vediamo /bin/ksh, allora è in esecuzione la shell di Korn, che è un super-insieme della shell di Bourne. La shell di Korn usa lo stesso prompt della shell di Bourne. Possiamo anche ottenere /bin/bash, e significa che stiamo usando al shell bash ( Bourne again shell ), che è parte del software di pubblico dominio GNU. Nel nostro caso, il comando echo $SHELL visualizza la stringa /bin/bash Se vediamo il prompt # invece del carattere $, allora stiamo operando con i privilegi del super-utente (system manager), l'amministratore del sistema. Questo non significa che modificando il prompt della shell automaticamente ci fornisca i poteri del super-utente. Le variabili della shell sono nominate usando le stesse regole generali del le variabili del linguaggio di 92

programmazione C. Una variabile di shell non richiede una dichiarazione esplicita, inizia ad esistere non appena iene referenziata, cioè richiamata in una assegnazione di assegnazione. Il valore iniziale di una variabile di shell è la stringa nulla (null). I valori delle variabili di shell vengono interpretate come stringhe, ma in alcuni contesti speciali, possono essere interpretati come numeri se sono stringhe numeriche, cioè composte da numeri. Il valore di una variabile di shell può essere incluso dappertutto in un programma scrivendo il nome della variabile preceduta dal carattere $. Sappiamo inoltre che un valore può essere assegnato ad una variabile di shell tramite la semplice assegnazione: variable name=stringa Notiamo che: Nell'assegnazione di una stringa ad una variabile di shell, non dovrebbe esserci nessuno spazio prima e dopo l'operatore di assegnazione = Es. se diamo l'assegnazione sistema= Linux otteniamo come risposta il messaggio: bash: Linux: command not found Il modo corretto di scrivere invece l'assegnazione è: sistema=linux senza alcuno spazio prima e dopo l'operatore = infatti, ora, dopo aver assegnato la stringa Linux alla variabile di shell sistema, visualizziamo il suo contenuto: $ echo $sistema Linux Otteniamo il contenuto della variabile sistema, senza alcun problema. La stringa non dovrebbe includere nessuno spazio interno. Proviamo a dare il comando echo peace In risposta, viene visualizzato sullo standard output (il monitor, nel nostro caso) la stringa peace. 93

Se il comando echo viene seguito da una lista di argomenti, questi vengono visualizzati sullo standard output. Ad esempio il comando echo peace love and joy visualizza sullo schermo le parole peace love and yoy Ora proviamo ad impostare una variabile di shell ad un valore particolare, assegnando quindi valore1=peace Per verificare che l'assegnazione è stata fatta correttamente, come abbiamo visto, scriviamo echo $valore1 Possiamo assegnare questo valore ad una nuova variabile di shell valore2=$valore1 Cosa succede se scriviamo echo $value2 $ valore1=peace $ echo $valore1 peace $ valore2=$valore1 $ echo $valore2 peace E cosa succede se scriviamo echo value2 value1 $value2 $value2 Inseriamo il comando nella shell echo valore1 valore2 $valore1 $valore2 Ed ecco il risultato valore1 valore2 peace peace 94

La shell supporta una varietà di convenzioni per racchiudere le stringhe tra apici, il che permette di scrivere valori stringa che incorporano spazi interni, apici singoli e doppi all'interno delle stringhe, ed anche il carattere $. Ad esempio, se vogliamo assegnare la frase la volpe pazza alla variabile frase, se scriviamo: frase=la volpe pazza vediamo cosa succede frase=la volpe pazza bash: volpe: command not found Doppi apici Per assegnare la stringa la volpe pazza alla variabile di shell frase, racchiudiamo la frase tra virgolette: frase= la volpe pazza Per verificare se l'assegnazione è stata fatta correttamente scriviamo echo $frase e vediamo il risultato ottenuto la volpe pazza Qualsiasi cosa che viene racchiusa tra i doppi apici viene passata alla shell esattamente come è inserita. L'unica eccezione è che i valori delle variabili di shell sono sostituite. Consideriamo il seguente esempio v1="a b c" Visualizziamo il valore della variabile ambientale v1 echo $v1 abc Ora creiamo la variabile ambientale v2, formata con la variabile di shell v1 e dalla lettera d v2="$v1 d" echo $v2 abcd 95

Cosa succede in questo caso? Succede che ogni volta che una variabile viene preceduta dal simbolo $, al posto della variabile viene sostituito il suo valore, e quindi, al posto di $v1 viene sostituito il suo valore e cioè a b c Visualizziamo ora le variabili v1 e v2: echo $v1 $v2 Questo comando produrrà il risultato abcabcd Apici singoli Qualsiasi cosa racchiusa tra apici singoli viene passata alla shell esattamente così come è. Es. v1='a b c' echo $v1 Ecco il risultato: abc I valori delle variabili di shell non vengono sostituiti. Consideriamo il seguente esempio v1="a b c" v2='$v1' Il comando echo $v2 visualizzerà la stringa $v1 Cambiamo il valore di v2 v2='$v1 d' 96

Il comando echo $v1$v2 produrra come output a b c$v1 d Perché? Back quotes (apici retroversi) Gli apici retroversi vengono usati per racchiudere i comandi. Fate attenzione ai caratteri apice singolo ', doppio apice e apice retroverso ` Ecco come si ottengono i caratteri specificati Apice singolo ' Sulla tastiera Doppio apice Sulla tastiera Apice retroverso (back quote) ` AltGr + ' Un elemento racchiuso tra apici retroversi viene rimpiazzato dall'output del comando. Ad esempio, consideriamo il seguente esempio oggi=`date` Il comando echo la data odierna è $oggi produrrà il risultato la data odierna è dom giu 5 18:00:56 CEST 2005 Consideriamo la seguente assegnazione della variabile di shell v1: v1=lupo il comando echo $v1 visualizzerà correttamente il valore assegnato alla variabile v1: echo $v1 ecco il risultato 97

lupo Consideriamo la nuova assegnazione v2=`$v1` Non appena confermiamo l'esecuzione di questa assegnazione, viene visualizzato il seguente messaggio: bash: lupo: command not found Perché succede ciò? Vediamo allora il funzionamento dell'assegnazione v2=`$v1`. Alla variabile ambientale v2 cosa viene assegnato? Quando la shell incontra la stringa $v1 racchiusa tra i back quotes (gli apici retroversi) capisce che è una variabile di ambiente, ma invece di prendere il suo valore, esegue direttamente il comando indicato da $v1 e restituisce il risultato, cioè il suo output, alla variabile v2. Come abbiamo visto con l'esempio precedente della data. Sappiamo che v1 contiene la stringa lupo. La shell allora cosa fa? Esegue il comando lupo (che chiaramente non esiste), ed ottiene un errore, perché il comando non viene trovato. Ricordiamo che un elemento racchiuso tra apici retroversi viene rimpiazzato dall'output del comando. Back Slash Il simbolo back slash \ può essere usato per disattivare gli effetti speciali di qualsiasi carattere singolo dopo il carattere back slash. Ad esempio, se volessimo assegnare alla variabile di shell la stringa a b non potremmo farlo usando l'assegnazione v1=a b infatti il comando echo $v1 produce il seguente risultato: bash: b: command not found Abbiamo già visto perché ciò succede. Avremmo dovuto scrivere v1= a b Volendo invece evitare gli apice possiamo scrivere v1= a\ b Il comando echo $v1 restituisce l'output ab 98

E' importante notare che le stringhe possono essere presentate alla shell più di una volta, nel qual caso può essere necessario usare il carattere \ per proteggere gli apici che potrebbero assumere un significato importante. Consideriamo il seguente esempio: Vogliamo eseguire il comando echo la data di oggi è `date` Vediamo il suo output la data di oggi è dom giu 5 19:09:53 CEST 2005 Il comando echo che abbiamo eseguito visualizza sullo schermo (lo standard output) la stringa o le stringhe che seguono. Nel nostro caso, la stringa era composta da due parti: 1. la data di oggi è 2. `date` Quando la shell incontra la stringa `date' racchiusa tra back quotes, cosa fa? Esegue il comando date, ed ottiene l'output dom giu 5 19:09:53 CEST 2005 che sostituirà al posto di `date` Quindi formerà la stringa completa concatenando le due parti: La data di oggi è + dom giu 5 19:09:53 CEST 2005 Questa stringa così formata sarà l'argomento del comando echo echo La data di oggi è dom giu 5 19:09:53 CEST 2005 Ora, complichiamo un poco le cose. Memorizziamo il comando echo La data di oggi è `date` in una variabile ambientale, che possiamo chiamare proprio comando comando=echo La data di oggi è `date` Il primo errore che abbiamo commesso è che non abbiamo racchiuso la stringa tra apici. Cosa succede se usiamo i doppi apici per delimitare la stringa? comando= echo La data di oggi è `date` Proviamo a visualizzare il contenuto della variabile comando echo $comando echo La data di oggi è dom giu 5 19:22:18 CEST 2005 Ci aspetteremmo che facendo eseguire più volte lo stesso comando, la data e l'ora mostrati sullo 99

schermo dovrebbero cambiare. Vediamo se succede, Ripetiamo il comando: echo $comando Il risultato sarà echo La data di oggi è dom giu 5 19:22:18 CEST 2005 Perché la data e l'ora visualizzata non cambiano? E poi, c'è qualche cosa di strano in questo comando! Analizziamo per primo la cosa strana. Noi abbiamo creato un comando che dovrebbe visualizzare la data e l'ora usando il comando echo, o, almeno, queste erano le nostre intenzioni. Ora invece il comando echo viene visualizzato come parte del messaggio sullo schermo. echo La data di oggi è dom giu 5 19:22:18 CEST 2005 La seconda cosa che vogliamo spiegarci è che la data e l'ora non cambiano, anche se eseguiamo più volte il comando echo $comando Questo è semplice da spiegare. Quando viene eseguita l'assegnazione comando= echo La data di oggi è `date' il comando date, racchiuso tra back quotes viene eseguito, e la data e l'ora che restituisce viene sostituito alla stringa `date' Quindi, in effetti, la nostra variabile comando conterrà sempre la data che è stata restituita la prima volta che è stata eseguita l'assegnazione. comando= echo La data di oggi è `date` Per fare in modo poi che il comando echo La data di oggi è `date` venga valutato come comando, costituito da echo + frase + date, dobbiamo usare, come abbiamo imparato, i back quotes: comando=`echo La data di oggi è `date`` Eseguiamo il comando echo $comando Ed ecco l'output prodotto La data di oggi è dom giu 5 19:44:24 CEST 2005 Come si vede, abbiamo risolto il problema, almeno il primo. Supponiamo si voler creare un comando che visualizzi la directory corrente. Memorizziamo il comando in una variabile di shell: 100

msg=`echo La tua directory corrente è \`pwd\`` e facciamolo eseguire: echo $msg La tua directory corrente è /home/padrone/tmp Alla fine la variabile si shell $msg rappresenta la lista di argomenti del comando echo La tua directory corrente è `pwd` L'effetto di tutto ciò è di impostare la variabile ambientale cms ad una stringa di caratteri, ad esempio La tua directory corrente è /home/padrone/tmp Notiamo che se cambiamo la directory corrente con il comando cd, la variabile di shell cmd contiene sempre il nome della vecchia directory corrente, ed abbiamo visto il perché. Una stringa può essere costruita concatenando variabili di shell o concatenando altre stringhe e variabili di shell. Ad esempio, creiamo le due variabili di shell x=fred y=paola Creiamo poi la variabile di shell z come concatenazione delle variabili x ed y: z=$x$y Il comando echo $z visualizza il contenuto della variabile di shell z: echo La nuova variabile contiene la stringa $z Il risultato sarà La nuova variabile contiene la stringa fredpaola Con questa operazione abbiamo concatenato due variabili di shell Se scriviamo z= La nuova stringa contiene $x$y abbiamo concatenato una stringa, La nuova stringa contiene, con le due variabili di shell, x ed y. 101

Può essere necessario, a volte, circondare il nome della variabile di shell (dopo il segno di dollaro) con parentesi graffe. In tal modo i nomi di variabili possono essere correttamente riconosciuti. Consideriamo il seguente esempio: x=fred y=joe z=$x$y Supponiamo di voler creare una nuova variabile u, concatenando la variabile di shell x con la stringa erick Se scriviamo u=$xerick facciamo un errore. Proviamo a visualizzare la variabile u con il comando echo echo $u Dopo che questo comando è stato eseguito, sul video non comparirà niente. Ciò si spiega facilmente. Con l'assegnazione u=$xerick assegniamo alla variabile u il contenuto della variabile xerick, che non abbiamo mai creato, e che quindi assume il valore null. Potremmo scrivere allora u=$x erick cioè concatenare una variabile di shell con una stringa oppure usare una diversa notazione, cioè racchiudere il nome della variabile x tra parentesi graffe u=${x}erick echo $z $u Questo comando produce le stringhe fredjoe frederick Le parentesi graffe sono esplicitamente richieste quando il simbolo immediatamente seguente è parte valida del nome del nome di una variabile di shell, cioè una lettera, un numero o il carattere underscore _. 102

SCRIPTING LANGUAGE I linguaggi di scripting (chiamati anche comunemente linguaggi di programmazione di scripting o linguaggi di script) sono linguaggi di programmazione per computer progettati per "scripting" l'operazione di un computer. I primi linguaggi di scripting erano spesso chiamati linguaggi di batch o linguaggi per il controllo dei lavori (job control languages). Uno script è solitamente interpretato più che compilato, ma non sempre. Nelle applicazioni per computer, uno script è un programma per computer che automatizza il tipo di lavoro che un utente altrimenti dovrebbe fare interattivamente tramite tastiera. Uno script di shell spesso consiste largamente di una sorta di comandi che dovrebbero essere scritti al prompt di comandi, o in un programma di word processing un utente dovrebbe scrivere uno script che potrebbe combinare una sequenza di compiti di editing che l'utente si aspetta di compiere ripetutamente. Molti di tali linguaggi sono abbastanza sofisticati, e sono stati usati per scrivere programmi elaborati, che spesso sono chiamati script anche se essi vanno oltre l'automazione di semplici sequenze di compiti dell'utente. Descrizione I linguaggi per il computer sono creati per vari scopi e compiti differenti tipi e stili di programmazione. Un comune compito di programmazione è noto come scripting, o connessione di diversi componenti preesistenti per svolgere un nuovo compito correlato. Questi linguaggi rivolti allo scripting sono tipicamente chiamati linguaggi di scripting (scripting languages). Molti linguaggi per questo scopo hanno proprietà in comune: favoriscono lo sviluppo rapido sull'efficienza di esecuzione; sono spesso implementati con interpreti piuttosto che con compilatori e sono forti nella comunicazione con componenti software scritti in altri linguaggi. Molti linguaggi di scripting emersero come strumenti per l'esecuzione di compiti non ripetitivi, particolarmente nell'amministrazione dei sistemi. Un modo di guardare agli script è coma se fosse la colla che mette insieme parecchi componenti; perciò sono ampiamente utilizzati per la creazione di interfacce grafiche utente (GUI). Gli script vengono tipicamente memorizzati solo in formato testo (come ASCII) ed interpretati, o (come con il linguaggio Perl) compilati ogni volta che vengono richiamati. Alcuni linguaggi di scripting sono progettati per un dominio specifico, ma spesso è possibile scrivere programmi più generali in quel linguaggio. IN molti progetti di larga scala, un linguaggio di scripting ed un linguaggio di programmazione di livello più basso sono usati insieme, ognuno portando i suoi principali punti di forza per risolvere specifici problemi. I linguaggi di scripting sono spesso progettati per l'utilizzo interattivo, avendo molti comandi che possono essere eseguiti individualmente, e spesso hanno operazioni di altissimo livello (per esempio, nella classica shell di UNIX (sh), molte operazioni sono esse stesse dei programmi). Tali comandi ad alto livello semplificano il processo della scrittura di codice. Caratteristiche di programmazione come gestione automatica della memoria e controllo dei limiti possono essere considerati come garantiti. In un linguaggio non di scripting, o di più basso livello, la gestione della memoria e delle variabili e la creazione di strutture dati tende a sprecare più tempo di programmazione e linee di codice per completare un compito assegnato. Normalmente, è più veloce programmare in un linguaggio di scripting, e di file di script sono tipicamente 103

molto più piccoli di, diciamo, un equivalente file di programma scritto in linguaggio C. L'altro lato della medaglia potrebbe essere una penalizzazione della performance: i linguaggi di scripting, spesso interpretati, possono essere significativamente più lenti da eseguire e possono consumare più memoria quando sono in esecuzione. In molti casi rilevanti, comunque, ad esempio con piccoli script di alcune decine di righe, il vantaggio del tempo di scrittura supera lo svantaggio del tempo di esecuzione. Ad ogni modo, il limite tra linguaggi di scripting e linguaggi di programmazione regolare tende ad essere vago. Tipi di linguaggi di scripting Linguaggi specifici dell'applicazione Programmi applicativi molto grandi includono un linguaggio di scripting adattato alle necessità dell'utente dell'applicativo. Inoltre, molti sistemi di computer game usano un linguaggio di scripting personalizzato per esprimere le azioni programmate degli oggetti non-player (quelli che non vengono controllati dal giocatore) e dell'ambiente del gioco. Linguaggi di questo tip sono progettati per una singola applicazione e, mentre possono superficialmente somigliare ad uno specifico linguaggio general-purpose (es. QuakeC, modellato sul C) essi hanno caratteristiche specifiche che li contraddistingue. Linguaggi per l'elaborazione del testo L'elaborazione di record basati su testo è uno degli usi più vecchi dei linguaggi di scripting. Molti, come awk e più tardi, Perl, furono originariamente sviluppati per aiutare gli amministratori di sistema nell'automazione dei task che implicavano i file di testo di configurazione ed i file di log. Perl è un caso speciale in origine inteso come un linguaggio per la generazione di report (da cui il suo nome, Practical Extraction and Reporting Language) si è poi sviluppato in un linguaggio di programmazione molto ricco. Linguaggi di controllo e shell Un'altra classe di linguaggi di scripting si è sviluppata dall'automazione del controllo dei task ( job control) -inizializzando e controllando il comportamento dei programmi di sistema. Molti di questi interpreti di linguaggi hanno anche una interfaccia a riga di comando, come la shell di UNIX oppure il COMMAND.COM di MSDOS. Altri, come AppleScript, aggiungono la capacità di scripting agli ambienti di elaborazione che mancano di una interfaccia a riga di comando. Linguaggi dinamici general-purpose Alcuni linguaggi, come Perl, hanno iniziato come linguaggi di scripting ma si sono sviluppati in linguaggi di programmazione adatti per scopi più ampi Altri linguaggi simili -- frequentemente interpretati, dinamici sono stati descritti come "linguaggi di scripting" per queste somiglianze, anche se essi sono molto comunemente usati per la programmazione di applicazioni. 104

Libreria standard del C La Libreria standard del C é una raccolta di header file e librerie di funzioni usate per implementare operazioni comuni, come l'input/output e l'elaborazione di stringhe nel linguaggio di programmazione C. Diversamente da altri linguaggi come il Pascal ed il PL/I, il C non include keyword integrate per questi scopi, quindi quasi tutti i programmi C si basano sulla libreria standard per funzionare. Il nome e le caratteristiche di ogni funzione sono incluse in un file chiamato header file ma l'implementazione vera e propria delle funzioni é in un file di libreria separato. I nomi e gli obiettivi degli header sono diventati comuni ma l'organizzazione delle librerie rimane non uniforme tra i vari compilatori. La libreria standard é solitamente inclusa con il compilatore. Dato che i compilatori C spesso forniscono funzionalità extra che non sono particolare specificate compilatore é nel spesso C ANSI, una incompatibile libreria con standard librerie con un standard di altri compilatori. Gran parte della libreria standard del C ha dimostrato di essere costruita bene. Qualche parte, con il senno di poi, é vista come mal costruita. La funzione di input gets() (e l'uso di scanf() per leggere input di stringhe) sono fonte di molti buffer overflow, e la maggior parte delle guide di programmazione raccomandano di non farne questo utilizzo. Un'altra stranezza é strtok(), una funzione che é costruita come un primitivo analizzatore lessicale ma é molto "fragile" e difficile da usare. Storia Il linguaggio C, prima di essere standardizzato, non aveva a disposizione alcune funzionalità come ad esempio le operazioni di I/O (diversamente da altri linguaggi tradizionali quali il Pascal ed il Fortran). Col passare del tempo, le comunità di utenti del C condivisero idee ed implementazioni di quelle che ora noi chiamiamo librerie standard del C per sopperire a queste mancanze. Molte di quelle idee furono incorporate nelle definizioni del linguaggio C standardizzato. Sia UNIX che il C furono creati ai laboratori Bell dell'at&t nei tardi anni 60 e nei primi anni 70. Durante gli anni 70 il linguaggio C divenne sempre più famoso. Molte università e organizzazioni iniziarono a creare le loro 105

variazioni del linguaggio per i loro progetti. Dagli inizi degli anni 80 iniziarono a diventare implementazioni del evidenti C. Nel problemi 1983 di l'ansi compatibilità (American tra National le varie Standards Institute) formò un comitato per stabilire una specifica standard del C conosciuto standard come C89 "C nel ANSI". 1989. Questo Parte lavoro dello culminò standard nella risultante creazione era un dello set di librerie chiamato libreria standard del C ANSI. Successive revisioni del C standard hanno aggiunto numerosi header file alla libreria. Il supporto per queste nuove estensioni dipende dalle implementazioni. Gli header <iso646.h>, <wchar.h>, e <wctype.h> furono aggiunti con il Normative Amendment 1 (d'ora innanzi abbreviato con NA1), un'aggiunta al C standard ratificata nel 1995. Gli header <complex.h>, <fenv.h>, <inttypes.h>, <stdbool.h>, <stdint.h>, e <tgmath.h> furono aggiunti con il C99, una revisione al C standard pubblicata nel 1999 Standard ANSI La libreria C ANSI standard consiste in 24 header file C che possono essere inclusi nel progetto di un programmatore con una singola direttiva. Ogni header consiste in una o più dichiarazioni di funzioni, definizioni di tipi e macro. Il contenuto di questi header file si può trovare più avanti. Rispetto ad altri linguaggi (per esempio il Java) la libreria standard è molto piccola. Questa dispone di un set base di funzioni matematiche, funzioni per la manipolazione di stringhe, conversione di tipi e I/O da file e da console. Non contiene un set standard di "contenitori di tipi" come la libreria standard dei template del C++, non dispone nemmeno di tool per creare interfacce grafiche per utenti (GUI), strumenti per la rete e molte altre funzionalità di cui dispone il Java. Il vantaggio principale di una libreria piccola e che è più facile fornire un ambiente ANSI C funzionante rispetto ad altri linguaggi, e conseguentemente è relativamente facile fare porting verso altre piattaforme. Molte altre librerie sono state sviluppate per fornire le funzionalità equivalenti a quelle a quelle fornite da altri linguaggi nelle loro librerie standard. Per esempio, il progetto di ambiente desktop GNOME ha permesso di 106

sviluppare il tool grafico GTK+ e la Glib, una libreria contenente strutture dati, e ci sono molti altri esempi conosciuti. La varietà di librerie disponibili è spiegabile con il fatto che alcune librerie, migliori di altre, hanno dimostrato la propria superiorità con il passare del tempo. Il problema insieme principale e i è che spesso programmatori che diverse librerie sono pratici non con alcuni funzionano set di bene librerie potrebbero trovarne set diversi su differenti piattaforme. stdlib.h stdlib.h è l'header file che, all'interno della libreria standard del C, dichiara funzioni e costanti di utilità generale: allocazione della memoria, controllo dei processi, conversione tra tipi e così via. È compatibile con il C++ ed è noto in quell'ambito con il nome cstdlib. Funzioni Le funzioni di stdlib.h possono essere classificate nelle seguenti categorie: 1. conversione tra tipi, 2. gestione della memoria, 3. controllo dei processi, 4. ricerca ed ordinamento, 5. matematica semplice. Nome Descrizione Conversione tra tipi atof Converte una stringa in un numero in virgola mobile. atoi Converte una stringa in un numero intero. atol Converte una stringa in un numero intero lungo (long int). strtod Converte una stringa in un double, effettuando dei controlli sull'overflow e restituendo anche l'eventuale parte non convertita della stringa. strtol Converte una stringa, che rappresenta un numero in una base arbitraria compresa tra 2 e 36, in un double (numero a 107

virgola mobile), effettuando dei controlli sull'overflow e restituendo anche l'eventuale parte non convertita della stringa. strtoul Equivalente a strtol() tranne per il tipo del risultato, che è unsigned long Allocazione e deallocazione di memoria calloc, malloc, realloc Funzioni memoria che si occupano dell'allocazione dinamica della free Libera la memoria allocata dinamicamente dalla famiglia di funzioni malloc() Controllo dei processi abort Causa la terminazione immediata ed anormale del programma, come se fosse stato invocato raise(sigabrt) atexit Registra una funzione, della quale le viene passato il puntatore, affinché venga eseguita appena prima della normale terminazione del programma. exit Causa la normale terminazione del programma. Tutte le funzioni registrate con atexit() vengono eseguite con ordine inverso rispetto alla loro registrazione, gli stream associati al programma vengono liberati, i file vengono scritti su disco (vedere flush()) ed il controllo viene restituito all'ambiente chiamante, assieme ad un valore numerico, che generalmente indica lo stato del programma o la causa della sua terminazione, che deve essere fornito alla funzione stessa. getenv Restituisce la stringa che nell'ambiente di lavoro del programma è associata al nome fornito, oppure NULL se non esiste alcuna stringa. I dettagli della funzione sono strettamente dipendenti dal sistema operativo. system Passa la stringa fornitole all'ambiente di lavoro per l'esecuzione e restituisce il codice d'uscita del comando invocato. Se si fornisce NULL, informa sulla eventuale presenza nel sistema di un processore di comandi. Ricerca ed ordinamento bsearch Implementa dicotomica in maniera generica l'algoritmo di ricerca qsort Implementa in maniera generica l'algoritmo di ordinamento quicksort Matematica semplice - presenti anche in math.h 108

abs, labs Calcola il valore assoluto dell'argomento. div, ldiv Calcola il quoziente ed il resto della divisione intera tra il dividendo ed il divisore forniti. 109

La lista di argomenti Ogni volta che un programma viene eseguito, una lista di argomenti di lunghezza variabile viene passata al processo. La lista di argomenti è un array di puntatori a stringhe di caratteri. C'è un limite superiore sulla dimensione della lista di argomenti, spesso di 5120 byte o 10240 byte. Normalmente un programma viene eseguito quando una riga di comando è inserita in un terminale. Per esempio, inviando la riga seguente: echo Ciao Mondo ad una shell di UNIX, viene eseguito il comando echo, a cui sono passate tre stringhe di argomenti, echo, ciao e mondo. Il processo sarà poi libero di fare ciò che vuole con questi argomenti, una volta che l'esecuzione è stata avviata. Un programma in C riceve la sua lista di argomenti dalla funzione di avviamento del C come argomento per la funzione main; questa è dichiarata come main (int argc, char* argv[]) Il primo argomento è un intero che specifica il numero di stringhe di argomenti. Questo numero è sempre maggiore o uguale ad uno, poiché ad un programma viene sempre passato almeno un argomento: il nome con cui viene chiamato. Il secondo argomento è un array di puntatori a stringhe di caratteri: argv argv[0] stringa argv[1] stringa argv[argc-1] stringa 110

Per esempio, per il comando echo, la rappresentazione è: argv argv[0] echo argv[1] ciao argv[2] mondo Il processo è libero di fare qualsiasi cosa con questi dati. 111

Lista di ambiente Ogni volta che un programma viene eseguito, ad esse viene passata una lista di lunghezza variabile di variabili di ambiente. Queste variabili sono passate alla funzione main del C come un array di puntatori alle stringhe del C, così come viene passata la lista di argomenti. Tuttavia, poiché non è disponibile un contatore dl numero di elementi di questo array di puntatori, esso deve essere terminato da un puntatore NULL. La lista di ambiente è accessibile al programma con un terzo argomento opzionale, envp, definito così: main (int argc,char* argv[], char* envp[]) Le stringhe di ambiente si presentano solitamente nella forma: variabile=stringa Vediamo come si visualizza la lista delle variabili di ambiente: #include <stdio.h> int main(int argc, char *argv[], char *envp[]) { int i; for (i=0;envp[i]!=null;i++) printf("%s\n",envp[i]); exit(0); } 112

Il comando wc per contare le parole di un testo Il comando wc (word count ovvero conta parole) per default conta il numero di righe, parole e caratteri presenti in un testo. Il comando wc definisce un testo come un insieme di lettere, numeri e/o simboli contigui separati dagli altri caratteri da uno o più spazi, tabulazioni e/o caratteri di newline (che sono generati quando viene premuto il tasto INVIO). Quando si contano i caratteri, vengono contati tutti i caratteri, non solo le lettere, numeri e simboli, ma anche gli spazi, tabulazioni e caratteri di newline. Una riga è contata solo se viene terminata dal carattere di newline. La sintassi del comando wc è la seguente: wc [opzioni] [nomi dei file] Gli elementi tra parentesi quadre sono opzionali. Se non viene fornito nessun nome di file, allora wc legge dallo standard input (per default è il testo introdotto da la tastiera) Lo possiamo vedere scrivendo wc alla riga di comando, premendo il tasto INVIO per spostarsi su una nuova linea e poi scrivere il testo su una o più righe. Il comando wc viene eseguito quando si preme di nuovo INVIO e poi premendo contemporaneamente i tasti CTRL e D. Questo fa sì che wc scriva in una nuova riga (sotto la riga del testo introdotto) il suo conteggio di righe, parole e 113

caratteri presenti nel testo. 114