Introduzione a UNIX


Pagina in costruzione
Aggiornata il 13 gennaio 1999

Indice

1 Introduzione
2 Sistemi informativi
3 Lo spazio utente (account)
4 Il grande fratello (super-user)
5 Collegamento (login)
6 Interfaccie macchina-utente
          6.1 L'interfaccia a riga di comando (CLI)
                    6.1.1 La riga di comando
                    6.1.2 La shell
          6.2 L'interfaccia grafica X
7 File e directory
          7.1 Cos'è un file
          7.2 Cos'è una directory
          7.3 L'albero delle directory e i percorsi
                    7.3.1 Percorsi relativi
                    7.3.2 Percorsi assoluti
                    7.3.3 Esempi di percorsi assoluti e relativi
          7.4 Non sempre la mamma è una sola (i link)
          7.5 Il file system
          7.6 Un esempio di file system
8 Programmi, comandi e processi
          8.1 Struttura dei comandi
                    8.1.1 Nomi dei comandi
                    8.1.2 Opzioni
                    8.1.3 Argomenti
          8.2 Input standard e output standard
                    8.2.1 Dispositivi e periferiche come file
          8.3 Redirezione dell'input e dell'output
          8.4 Composizione di comandi
9 Comandi principali
          9.1 Il comando principale (man)
          9.2 Elencare file e directory (ls)
          9.3 Visualizzare e cambiare la directory corrente (pwd, cd)
          9.4 Creare una directory (mkdir)
          9.5 Copiare file e directory (cp)
          9.6 Rinominare e spostare file e directory (mv)
          9.7 Eliminare e spostare file e directory (rm, rmdir)
          9.8 Creare dei link (ln)
10 Manipolazione avanzati di file e directory
          10.1 Concatenare e suddividere dei file (cat, split)
          10.2 Filtrare righe in file di testo (grep)
          10.3 Tagliare e incollare colonne di testo (cut, paste)
          10.4 Ordinare un file di testo (sort, uniq)
          10.5 Cercare file e directory (find)

1 Introduzione

UNIX è un sistema operativo, cioè un complesso di comandi e funzionalità che consentono ad un essere umano di ottenere dei servizi di vario tipo da un sistema informativo costituito da uno o più elaboratori elettronici e altri dispositivi fra loro collegati.

UNIX è multi-utente: consente simultaneamente a più persone, o utenti, di accedere allo stesso sistema informativo, e alle risorse di esso, da diversi punti di accesso, costituiti in genere da terminali di vario tipo che potrebbero essere localizzati ovunque nel mondo. Uno stesso utente può accedere al sistema informativo da più punti nello stesso momento, se ne ha la possibilità materiale.

UNIX è multi-tasking: in qualunque momento ogni utente può chiedere al sistema informativo l'esecuzione di qualsiasi compito, anche se già altri utenti stanno usufruendo delle stesse funzionalità, o se l'utente stesso ha già fatto la stessa richiesta.

UNIX è un sistema operativo di rete: un utente può utilizzare risorse che si trovano fisicamente molto lontano da lui, e può facilmente comunicare con altri utenti.

UNIX è molto collaudato, ben più stabile dei sistemi operativi usati nell'informatica personale, e molto meno vulnerabile ai virus. Naturalmente ha i suoi punti deboli, ma la stabilità complessiva di un sistema UNIX è largamente superiore, almeno per ora, a quella ottenibile con i sistemi utilizzati nell'informatica personale.

UNIX dispone di una interfaccia grafica molto potente, anche se meno facile da usare di quelle fornite da altri sistemi: l'interfaccia X, spesso chiamata anche X-Windows, sviluppata al MIT e da considerarsi ormai molto stabile ed affidabile.

UNIX è molto usato nella ricerca, in parte per tradizione, in parte perché offre strumenti e prestazioni finora non raggiunte da altri sistemi, ed è più adatto al lavoro di gruppo e allo scambio di informazioni fra gruppi di ricerca nel mondo. Si può ben dire che è nato proprio per questo, e non a caso è nato nell'ambiente accademico.

2 Sistemi informativi

Presentiamo ora un modello molto approssimativo di sistema informativo. Il parallelo con la struttura di un essere umano, che verrà usato nel seguito, è alquanto ardito, e non va ovviamente preso troppo alla lettera. Tuttavia si è ritenuto piuttosto pratico in questo contesto.

Un sistema informativo è come una persona alla quale si possono rivolgere domande, impartire comandi, dare informazioni e, più in generale, richiedere servizi legati alla gestione delle informazioni.

Invece di tentare di offrire una definizione più rigorosa, vediamo quali sono le componenti più importanti di un sistema informativo, proseguendo nel parallelo con l'essere umano.

3 Lo spazio utente (account)

Abbiamo detto che UNIX consente a vari utenti di accedere, anche simultaneamente, alle risorse offerte da un sistema informativo. Queste risorse non sono soltanto rappresentate dalla possibilità di ottenere informazioni dal sistema, ma anche dalla possibilità di memorizzare queste informazioni in uno spazio opportuno. Se questo spazio fosse comune a tutti gli utenti, sarebbero inevitabili conflitti fra gli utenti che intervengono su di esso. UNIX invece assegna a ogni utente uno spazio ben definito, che appartiene solo a quel particolare utente e non può essere modificato dagli altri utenti. All'interno di questo spazio, che chiameremo account come in inglese, l'utente può manipolare a suo piacimento le informazioni che lo interessano, creare nuovi modi per elaborarle, o generarne di nuove. Può memorizzare la sua corrispondenza (e-mail) con altri utenti, può cercare in tutto il mondo le informazioni che lo interessano e memorizzarle per usi futuri e fare molte altre cose, senza mai interferire con il lavoro degli altri utenti, almeno entro ragionevoli limiti.

È bene tenere presente che l'account è uno spazio virtuale, nel senso che l'utente non vede, di solito, lo spazio fisico che gli è stato assegnato, e può ignorare la locazione reale di questo spazio, e addirittura la sua stessa natura: infatti quella che egli ritiene essere memoria di massa, può a volte essere in realtà memoria RAM, che gli viene presentata come memoria di massa . Viceversa, risorse di memoria di massa, cioè spazio su disco, possono essergli presentate come memoria RAM. Tuttavia egli non deve preoccuparsi, entro certi limiti, della reale natura delle risorse che gli vengono offerte, in quanto esse sono gestite dal sistema, in genere nel migliore dei modi.

4 Il grande fratello (super-user)

Gli utenti di un sistema UNIX non sono tutti uguali: c'è un utente che può fare molte cose negate agli altri, fra cui:

Questo utente, detto amministratore di sistema o super-user, ha prerogative che lo rendono in effetti una specie di grande fratello, per il quale non ci sono segreti. Ovviamente, queste prerogative lo caricano anche di pesanti responsabilità.

5 Collegamento (login)

Per accedere ad un sistema informativo operante sotto UNIX, l'utente deve innanzitutto essere registrato come tale. Egli deve aver fornito i suoi dati al super-user, il quale gli assegna un account con un suo spazio di memoria permanente e soprattutto una coppia di parole: lo username e la password. La prima parola è il nome col quale il nuovo utente sarà riconosciuto sia all'interno del sistema, sia al suo esterno. La seconda parola è segreta, e serve al sistema per assicurarsi dell'identità dell'utente stesso. Dopo aver ricevuto dal super-user una password, il nuovo utente può accedere per la prima volta al sistema inserendo username e password in risposta ad esplicite richieste da parte del sistema.

Il processo di collegamento, riconoscimento e abilitazione di un utente registrato sul sistema sarà chiamato nel seguito più brevemente come login. Esso può avvenire in molti modi diversi, per lo più utilizzando dei terminali opportuni, ma in ogni caso l'utente vedrà apparire sullo schermo la sequenza

login:
e dovrà allora inserire il proprio username, confermandolo con il tasto ENTER (o RETURN), presente sulla tastiera del terminale. Poi gli verrà richiesta la password, tramite la sequenza
password:
e anche in questo caso, digitata la propria password (che non sarà visualizzata sullo schermo), l'utente dovrà confermare con ENTER.

6 Interfaccie macchina-utente

Una volta realizzato il login, tutto quello che l'utente ha ottenuto è solo di essere stato riconosciuto come tale dal sistema. Egli però ha bisogno di interagire col sistema attraverso una qualche interfaccia che aiuti a colmare, almeno in parte, l'abisso che separa il modo di ragionare umano, che è tipicamente associativo, dal modo di ragionare, se così si può chiamare, della macchina, che è invece tipicamente sequenziale e ripetitivo.
A un primo livello di interazione fra questi due mondi si trovano due tipi principali di interfaccia, che ora approfondiremo.

6.1 L'interfaccia a riga di comando (CLI)

L'interfaccia a riga di comando, che in seguito chiameremo CLI (dall'inglese Command Line Interface) è una modalità di interazione fra l'uomo e la macchina piuttosto primitiva, ma nello stesso tempo estremamente versatile e potente, soprattutto nei casi, tutt'altro che infrequenti, in cui l'utente debba eseguire un compito molto particolare un gran numero di volte, o semplicemente molto spesso.

6.1.1 La riga di comando

La CLI si chiama così perché l'utente impartisce i comandi al sistema digitandoli sulla tastiera e controllandone l'esattezza vedendoli apparire su una opportuna riga dello schermo, detta riga di comando, appunto command line in inglese. Questa linea si distingue dalle altre grazie a una sequenza di caratteri più o meno significativi detta prompt. La parola vuol dire in effetti pronto, e indica all'utente che il sistema è pronto ad eseguire i comandi impartiti, e che questi compariranno proprio in quella posizione, subito dopo il prompt.
I seguenti sono tipici esempi di prompt:

#
$
[Sep 20, 4:45pm]$
ares:45>
A parte i primi due, che si limitano a indicare la posizione in cui appariranno i comandi digitati, gli altri due sono esempi di prompt che forniscono altre utili informazioni all'utente, quali la data, oppure il nome della macchina a cui è collegato l'utente e il numero dei comandi finora impartiti nell'attuale sessione di lavoro.
I seguenti invece sono esempi di righe di comando in cui l'utente ha già digitato qualche comando:
# mount -F nfs phobos:/export/home /import/phobos/home
[Sep 20, 4:45pm]$ ls -l | grep core
ares:45> rm -rf ~
I comandi impartiti devono essere sempre confermati battendo il tasto ENTER o RETURN presente su tutte le tastiere.

6.1.2 La shell

Una volta confermato il comando digitato sulla riga di comando, esso viene gestito da un programma molto speciale, detto shell in inglese. La shell è in sostanza l'interprete dei comandi impartiti dall'utente, e può fare molto più di questo. In particolare, è in grado di eseguire sequenze anche molto complesse di comandi, fornendo così all'utente un vero e proprio linguaggio di programmazione.

Per prima cosa la shell controlla che il comando impartito risponda ad una certa sintassi. Infatti la shell non accetta comandi battuti a caso, ma pretende che l'utente parli la sua lingua, altrimenti rifiuta caparbiamente di fare ciò che questi vorrebbe.

Verificata la sintassi dal suo proprio punto di vista, la shell passa il controllo al comando stesso, e quando esso ha terminato il suo compito, presenta i risultati all'utente.
Ci sono molti tipi di shell, che si differenziano fra loro per diversi motivi:

Ovviamente non esiste una shell perfetta: per la maggior parte degli utenti, che non ha bisogno di usare la shell come linguaggio di programmazione, le funzioni di edizioni della riga di comando sono più importanti degli aspetti legati alla programmazione. Per l'amministratore di sistema questi possono invece essere i più rilevanti.
Le shell più famose sono:

6.2 L'interfaccia grafica X

L'interfaccia grafica è completamente diversa dalla CLI, ma non si deve dimenticare che dietro di esse c'è comunque un'interprete di comandi, una qualche shell, che esegue i comandi impartiti dall'utente usando strumenti grafici.
L'interfaccia grafica presenta all'utente, sullo schermo, delle finestre (regioni rettangolari dello schermo, delimitate da un bordo ben visibile) che egli, in genere, può spostare, ridimensionare e chiudere utilizzando il mouse. Nelle finestre possono esserci bottoni, barre di scorrimento del testo, cursori, menù di opzioni, e molti altri oggetti attraverso i quali l'utente agisce sulle informazioni in un modo certamente molto più pratico che non con la shell.

Esempio di finestre in ambiente X

Ci sono poi applicazioni e funzionalità che hanno senso che sembrano fatte apposta per essere gestite in modo visuale, e che sarebbero praticamente irrealizzabili con una CLI.
Anche molte funzionalità già fornite via CLI si rivelano molto più comode nella versione grafica.

7 File e directory

Gli oggetti con cui l'utente si trova più frequentemente ad operare sono senz'altro i file e le directory. Dal punto di vista di UNIX essi sono qualcosa di piuttosto astratto, ma nel presente contesto non tenteremo di dare una definizione rigorosa, cercando piuttosto di fornire delle nozioni pratiche.

7.1 Cos'è un file

Un file è un sottoinsieme della memoria del sistema. Questa definizione è tutt'altro che astratta: dal punto di vista dell'utente è più che sufficiente sapere questo, con una piccola ma rassicurante aggiunta: i file vengono in genere registrati nella memoria di massa. Questo significa che l'utente li ritroverà al loro posto dopo molto tempo, anche se il sistema è stato disattivato.

Poiché però un file può essere trasferito dalla memoria di massa alla RAM, elaborato in essa, e poi ritrasferito nella memoria di massa, non è utile pensare ai file solo come oggetti che risiedono sui dischi rigidi o sui nastri.

Il fatto è che un file è una importante unità di memorizzazione, estremamente versatile, che consente di rappresentare praticamente qualsiasi cosa: testi, formule, immagini, suoni, tabelle di dati, grafici, programmi e così via.

Come può avvenire tutto questo, se un file, come sottoinsieme della memoria di sistema, è solo una sequenza di byte? Un primo ovvio esempio è la rappresentazione di un testo in un file: facendo corrispondere in maniera biunivoca una lettera a un numero compreso fra 0 e 255 possiamo facilmente realizzare questo obiettivo. Essendo questa un'esigenza fondamentale in un sistema informativo, è stato da tempo fissato uno standard, detto ASCII dal nome dell'autorità statunitense per gli standard, che stabilisce appunto una ben precisa corrispondenza fra lettere e numeri.

Un file in cui ogni byte rappresenta una lettera all'interno di un testo di senso compiuto viene detto file di testo, o anche file ASCII.

Molti altri tipi di informazione possono essere rappresentate da una sequenza di byte, ma quello che è importante capire è che un file non ha un significato di per sè. Esso assume un significato quando viene utilizzato dal programma stesso che lo ha generato, o da un programma che risponda allo stesso standard adottato dal programma creatore.

7.2 Cos'è una directory

Un tipo particolare di file sono le directory, che possono contenere altri file, e anche altre directory, secondo una tipica struttura ad albero. Le directory sono in genere utilizzate per mantenere ordine nell'account, disponendo in una stessa directory file fra loro logicamente legati, e tenendoli separati da altri file, a loro volta contenuti in altre directory.

A seconda del contesto, può essere pratico paragonare una directory a una qualche entità molto familiare. In questa fase conviene pensare alle directory come a dei cassetti molto particolari che, a differenza dei cassetti veri e propri, oltre a contenere oggetti vari (calzini, lenzuola, fazzoletti), possono contenere altri cassetti, che a loro volta possono vari oggetti e altri cassetti ancora, e così via.

7.3 L'albero delle directory e i percorsi

Per acquisire familiarità con file e directory può essere comodo paragonare questi enti a delle persone. In quest'ottica si stabiliscono delle parentele fra file e directory che possono essere relative (come quando si parla di zio, nipote, cugina), oppure assolute (come quando si dice che Giorgio è figlio di Flavia, o che Riccardo è zio di Francesca). Queste parentele sono espresse tramite i percorsi che descrivono una sorta di albero genealogico, che chiameremo nel seguito albero delle directory. In questo albero i file equivalgono a persone che non hanno figli, mentre le directory equivalgono a persone che hanno qualche figlio. Solo per semplicità useremo il genere femminile per le directory e il genere maschile per i file.

7.3.1 Percorsi relativi

Una persona in genere parla di sé come "io" o "me", e di sua madre come "mamma", anche se ovviamente ogni persona ha un nome diverso e una madre diversa. Nel parallelo fra persone e directory, il posto della parola "io" è preso dal simbolo "." (il punto finale). La directory in questione viene anche detta directory corrente, ed è quella in cui si presume che si trovino, in mancanza di altre indicazioni, i file (o altre directory) che l'utente, attraverso comandi o programmi, vuole manipolare. La madre della directory corrente è invece individuata dal simbolo "..", corrispondente banalmente al generico "mamma".

Una directory qualsiasi, come qualunque madre, chiama i suoi eventuali figli per nome, siano essi dei file o altre directory; ad esempio, giorgio, laura e luisa-giovanna sono possibili figli e figlie della directory corrente. Si noti come i nomi non siano preceduti da alcun simbolo particolare.

Più in generale, per individuare nipoti, nonne, cugine o altro, dalla directory corrente occorre indicare tutte le parentele intermedie, separandole col simbolo "/". Ad esempio, la nonna della directory corrente è ../.., la bisnonna è ../../.. e così via. Allo stesso modo, una nipote (figlia della figlia) potrebbe essere franca/carla, un pronipote franca/carla/giovanni, una sorella ../laura e un cugino di primo grado ../../claudia/valerio.

7.3.2 Percorsi assoluti

Il simbolo "/", usato da solo, o all'inizio di una sequenza come quelle appena viste, fa riferimento all'antenata comune a tutte le directory, una specie di Eva, detta solitamente directory radice, con chiaro riferimento all'immagine dell'albero. Così, ad esempio, qualunque sia la directory corrente, con /franca/carla/giovanna si intende una ben precisa directory, ben diversa, a priori, da franca/carla/giovanna (a meno che la directory corrente non sia proprio la radice.

I percorsi che iniziano dalla radice si dicono percorsi assoluti. Usare un percorso assoluto è come chiamare una persona per nome e cognome, piuttosto che chiamarla papà o zia. Tuttavia, mentre fra le persone possono aversi omonimie, esse non possono aversi fra le directory e i file quando si usano percorsi assoluti. Il percorso assoluto di una directory o di un file è univoco.

7.3.3 Esempi di percorsi assoluti e relativi

Per fissare le idee riguardo ai percorsi è utile fare qualche esempio che metta in evidenza le relazioni fra i percorsi assoluti e quelli relativi.

Esempio di albero di directory

Assumiamo come directory corrente è, in senso assoluto, /carla/giovanna/marcella (vedi figura). Allora il percorso relativo ../renata, corrispondente al percorso assoluto /carla/giovanna/renata, individua una sorella della directory corrente.

Analogamente, con ../../roberta (cioè /carla/roberta) si individua una sorella della madre della directory corrente, e quindi una zia.

Invece, con ../../roberta/marcella (cioè /franca/carla/roberta/marcella) si individua una cugina della directory corrente che ha, casualmente, il suo stesso nome, la stessa nonna (/carla), ma un'altra madre (/carla/roberta), ed è pertanto diversa dalla directory corrente.

Dalla figura si vede inoltre che /carla/giovanna/marcella e /carla/giovanna/renata, che sono sorelle, hanno entrambe un figlio che si chiama franco, ma la seconda ha anche un altro figlio che si chiama giuseppe. Essi hanno in comune con claudio, figlio di /carla/roberta/marcella, la bisnonna /carla. Tutti e quattro possono chiamare la bisnonna col nome ../../.. invece che col suo nome proprio.

7.4 Non sempre la mamma è una sola (i link)

L'incesto, che nella società occidentale è considerato un abominio, si rivela invece molto utile per accedere ad un file o a una directory in maniera più diretta che con il suo percorso, assoluto o relativo che sia. Inoltre, può fare comodo poter fingere che un file si trovi in una certa directory, o anche in molte directory, sebbene esso si trovi in realtà soltanto in una.

Per questo esistono i collegamenti, che nel seguito chiameremo link come in inglese (si veda più avanti come si crea un link). Un link è una specie di sinonimo per un file o una directory che può anche trovarsi in una directory diversa da quella in cui si trova il link. In particolare, questo meccanismo può alterare la struttura ad albero delle directory, portando a situazioni in cui un'apparente nipote è in realtà la nonna o anche peggio. Pertanto i link realizzano a tutti gli effetti le forme più turpi di incesto all'interno della famiglia delle directory.

Esempio di albero con dei link

Dal punto di vista dell'utente, avere dei link può servire a risparmiare spazio, riproducendo in una qualsiasi directory una serie di file o directory senza realmente copiarle. È importante capire che il link è a tutti gli effetti identico al file originale, e ogni modifica sull'uno si ripercuote sull'altro, proprio come se fossero la stessa cosa. L'unica differenza è che rinominare, spostare o cancellare un link non ha alcun effetto sul file originale.

Come esempio di uso dei link, facendo riferimento alla figura sopra, vediamo che la directory /carla contiene un link alla sua nipote /carla/giovanna/renata. Pertanto tale directory può ora essere indicata anche come /carla/renata. Anche la directory /carla/roberta contiene ora un link a /carla/giovanna/renata, che dunque può essere indicata anche come /carla/roberta/renata.

Analogamente, il figlio claudio di /carla/roberta/marcella, è ora anche figlio di /carla/giovanna/renata, e quindi può essere chiamato con uno dei seguenti nomi:

/carla/roberta/marcella/claudio
/carla/roberta/renata/claudio
/carla/giovanna/renata/claudio
È importante capire che nessuno di questi link consiste in una copia fisica del file (o della directory), e quindi non è stato creato spazio in più per consentire a renata di fare riferimento a claudio come se fosse suo figlio, né a carla e roberta di fare riferimento a renata come propria figlia.

7.5 Il file system

Il parallelo con i rapporti di parentela, leciti o meno, può essere istruttivo, ma tecnicamente non è molto ortodosso. In particolare, è importante capire che, in UNIX, non solo i dischi (rigidi o flessibili), ma quasi tutti i dispositivi possono essere interpretati come file e directory, e tutti insieme, partendo dalla directory radice, formano il cosiddetto file system. Questa può sembrare una assurda forzatura, ma bisogna tener presente che la maggior parte dei dispositivi che il sistema deve gestire non fanno altro che trasmettere informazioni al sistema, in entrata e in uscita, sotto forma di sequenze ordinate di byte, che vengono opportunamente interpretate dal sistema e dai dispositivi. Ma una sequenza di byte è proprio quello che abbiamo definito come file! Non deve quindi sorprendere che una stampante, un disco esterno, un lettore CD-ROM, un mouse, un modem e molti altri dispositivi siamo visti da UNIX come altrettanti file, ciascuno dei quali ha un nome e una collocazione ben precisi.

È anche importante capire che ogni file, che rappresenti un vero e proprio archivio su disco o un dispositivo, e qualunque sia la sua collocazione fisica, apparirà sempre come un discendente, pi`u o meno remoto, della madre di tutte le directory: la radice ("/"). Il sistema, e a volte l'amministratore o l'utente qualunque, provvede a realizzare questa corrispondenza. Ma per fissare le idee è utile fare qualche esempio.

7.6 Un esempio di file system

I diversi dialetti di UNIX non sono purtroppo molto coerenti fra loro nella struttura del file system. Tuttavia quasi tutti hanno le seguenti directory, che in genere sono visitabili (si veda più avanti), ma non scrivibili, da tutti gli utenti registrati sul sistema.

8 Programmi, comandi e processi

Abbiamo già incontrato il termine programma. Richiamiamo ora questo concetto, introducendo anche i concetti di comando e applicazione, nonché quello di script:

8.1 Struttura dei comandi

La struttura più semplice di un comando UNIX è la seguente:

# nome_comando opzioni argomenti
Più avanti (redirezione, composizione) si vedranno altri dettagli, ma per il momento esaminiamo solo queste tre parti.

8.1.1 Nomi dei comandi

I nomi dei comandi UNIX sono tipicamente sigle derivate da parole inglesi, spesso composte di sole due lettere. Questo rende facile dimenticare i nomi dei comandi usati più raramente, ma consente di risparmiare tempo nel digitare i comandi quando si dispone solo di un'interfaccia di tipo CLI. D'altronde, UNIX è nato quando i comandi si impartivano tramite schede perforate...

Tipici esempi di nomi di comandi sono ls, cp, lp, rm e moltissimi altri. È davvero raro che un comando UNIX abbia un nome più lungo di 4 lettere.

8.1.2 Opzioni

Le opzioni ad un comando servono a specializzare il comportamento di esso, in modo da ottenere risultati diversi a seconda delle esigenze dell'utente. Ovviamente però un'opzione non porta mai a stravolgere completamente lo scopo del comando.

A seconda dei comandi, ogni opzione deve essere preceduta dal simbolo "-" (trattino) oppure no. Quasi sempre le opzioni sono costituite da singoli caratteri, in genere lettere, e in questo caso si possono specificare molte opzioni insieme usando un solo trattino, come nel comando:

# ps -eflcj
in cui sono specificate cinque opzioni.

A volte le opzioni richiedono dei parametri (numerici o alfanumerici). In questi casi c'è un'importante differenza fra i comandi che richiedono opzioni col trattino e gli altri: nei primi le opzioni devono essere subito seguite dall'eventuale parametro (modulo uno spazio fra l'opzione e il parametro), mentre nei secondi prima si indicano tutte le opzioni, poi gli eventuali parametri richiesti da alcune di esse, nell'ordine in cui si trovano le opzioni corrispondenti.

Per fissare le idee, l'esempio seguente mostra quattro modi diversi di ottenere lo stesso risultato con un comando che richiede opzioni col trattino, e in cui l'opzione "-o" richiede un elenco di parole separate da virgole:

# ps -e -f -o pid,fname,user
# ps -efo pid,fname,user
# ps -eo pid,fname,user -f
# ps -o pid,fname,user -fe
Nel caso di un comando che richiede opzioni senza trattino, si scrivono prima le opzioni, tutte di seguito, e poi eventuali parametri, Anche in questo caso, il risultato delle quattro scritture è lo stesso:
# ufsrestore ifs sauron:/dev/nrmt0h 4
# ufsrestore isf 4 sauron:/dev/nrmt0h
# ufsrestore sif 4 sauron:/dev/nrmt0h
# ufsrestore -sfi 4 sauron:/dev/nrmt0h
Per distinguere i due casi, che sono spesso strettamente legati al tipo di UNIX che si utilizza, la cosa migliore da fare è controllarne la sintassi usando il comando man.

8.1.3 Argomenti

Molti comandi richiedono degli argomenti su cui operare. Essi sono in genere separati da spazi, e possono essere in numero variabile. Ad esempio, il comando cat richiede zero o più nomi di file come argomenti. Al contrario, ci sono comandi che non richiedono alcun argomento, come ad esempio ps, che prevede molte opzioni, ma nessun parametro.

8.2 Input standard e output standard

La maggior parte dei comandi si possono considerare come delle funzioni dell'insieme di tutti i file possibili in se stesso. Il file che fa da variabile indipendente si chiama file di input standard, o anche standard input, mentre il file che fa da valore della funzione-comando si chiama file di output standard, o anche standard output.

Ma per capire meglio quanto sopra occorre una piccola digressione.

8.2.1 Dispositivi e periferiche come file

In UNIX, come accennato sopra, il concetto di file è piuttosto astratto. Ma questa astrazione ha i suoi vantaggi: infatti consente di mettere in evidenza l'essenza del modo in cui l'informazione fluisce attraverso un sistema informativo, e cioè semplicemente come un flusso di byte, anche se questi vengono poi organizzati e utilizzati in modi più o meno complessi.

Ad esempio, la tastiera può inviare al sistema una sequenza di caratteri, un solo tasto alla volta. E lo schermo, in fondo, fa la stessa cosa (anche se così velocemente da dare l'impressione che molti oggetti appaiano simultaneamente). Ma allora, perché non considerare tastiera e schermo come dei file? È appunto ciò che avviene in UNIX come in molti altri sistemi operativi, e non solo per la tastiera e lo schermo.

In particolare, la tastiera corrisponde all'input standard e lo schermo corrisponde all'output standard. Pertanto, quando l'utente digita dei dati su richiesta di un programma o di un comando, quest'ultimo non fa altro che leggerli dall'input standard, e quando un programma visualizza dei dati sullo schermo, si limita a scriverli nell'output standard.

Più in generale, si considerano come file le stampanti, gli scanner, i mouse, i modem e praticamente ogni altro tipo di dispositivo.

8.3 Redirezione dell'input e dell'output

Questa astrazione del ruolo di due oggetti molto materiali come tastiera e schermo può sembrare del tutto accademica. Ma così non è. Quando infatti un programma richiede in ingresso parecchi dati, è molto scomdo inserirli a mano uno dopo l'altro, magari sbagliando proprio l'ultimo! È molto meglio inserirli in un file di testo, nell'ordine richiesto, e poi indicare al programma che l'input standard non è più la tastiera, ma il file appena creato. Per fare questo si usa la seguente sintassi:

# nome_del_programma < nome_del_file_di_dati
(trascurando per semplicità le opzioni e gli argomenti, che vanno comunque scritti prima del segno "<").
Analogamente, può capitare che il programma produca in uscita un cospicuo flusso di dati che vengono di norma visualizzati sullo schermo, e una sola volta. Può essere utile registrare questi risultati in maniera permanente per poi esaminarli con calma, e magari riutilizzarli per ulteriori elaborazioni. Riprendendo l'esempio sopra, useremo allora la sintassi:
# nome_del_programma > nome_del_file_di_risultati
(trascurando ancora opzioni e argomenti). Questa volta abbiamo informato il programma che l'output standard non è più lo schermo, ma il file di cui sopra, che il programma creerà scrivendoci quello che avrebbe scritto sullo schermo.

Quello che abbiamo appena visto è appunto la redirezione dell'input e dell'output. E ovviamente si possono combinare le due cose, come nei due esempi sotto:

# nome_del_programma < nome_del_file_di_dati > nome_del_file_di_risultati
# nome_del_programma > nome_del_file_di_risultati < nome_del_file_di_dati 
I vantaggi offerti dalla redirezione sono particolarmente evidenti nei casi in cui l'utente scrive un proprio programma per realizzare simulazioni numeriche, e deve fare parecchi esperimenti per portare il programma ad un buon livello di affidabilità, nonché per ottenere infine dei risultati da presentare: registrare su una serie di file sia i dati in ingresso, sia i risultati in uscita è utlissimo, se non addirittura necessario, per ottenere questi obiettivi.

8.4 Composizione di comandi

Come estensione della redirezione dell'input e dell'output vediamo ora la possibilità di comporre più comandi (o programmi) di seguito. Ripensando ai programmi come funzioni dell'insieme di tutti i file possibili in se stesso, la composizione di comandi è pressocché equivalente alla composizione di funzioni. L'operatore di composizione per i comandi è il simbolo "|" (barretta verticale), che spesso chiameremo pipe (tubo) come in inglese. Questo termine in effetti richiama l'idea di mettere dei tubi uno di seguito all'altro, formando una tubatura attraverso la quale fluisce l'informazione. Per contro, questa idea non evidenzia il fatto, fondamentale, che ogni singolo comando della catena effettua una trasformazione sull'informazione.

Ma prima di vedere come si compongono dei comandi, vediamo perché può avere senso farlo. Innanzitutto, perché stiamo parlando solo di composizione di comandi, e non di composizione di programmi? Fermo restando che tutto quanto segue vale per qualsiasi tipo di programma, parleremo soprattutto di comandi in quanto essi hanno in genere delle finalità estremamente specializzate e limitate, e quindi, per ottenere elaborazioni complesse usando dei comandi è quasi sempre necessario utilizzarne più di uno. Ecco perché ha senso soprattutto comporre dei comandi, anche se è perfettamente lecito fare lo stesso con qualsiasi programma, script compresi. Vedremo più avanti esempi concreti.

Ora vediamo come combinare fra loro n comandi:

# comando_1 | comando_2 | ... | comando_n
Si noti che ogni comando della catena può avere delle opzioni, ma solo il primo può avere un input diverso dallo standard, e solo l'ultimo può inviare il suo eventuale output a un file, come visto sopra. Quindi si può al massimo avere la situazione seguente:
# comando_1 < file_di_dati | comando_2 | ... | comando_n > file_di_risultati
Questo non deve sorprendere, in quanto in una composizione di comandi avviene in realtà una cosa semplicissima: ogni comando invia il suo output al comando successivo, che considera questo output come proprio input. In pratica è come se avessimo dato la seguente serie di comandi separati:
# comando_1 < file_di_dati > file_temporaneo_1
# comando_2 < file_temporaneo_1 > file_temporaneo_2
# ...
# comando_(n-1) < file_temporaneo_(n-2) > file_temporaneo_(n-1)
# comando_n < file_temporaneo_(n-1) > file_di_risultati
È evidente la comodità dell'operatore di composizione rispetto ad una simile sintassi. Ma vediamo subito qualche esempio concreto.

Per sapere la lunghezza complessiva di tutti i file con estensione "*.ps" che si trovano nell'albero di directory dell'utente giuliano:

# find ~giuliano -name "*.ps" -ls | awk 'BEGIN {s = 0} {s += $1} END {print s}'
Per ottenere una lista degli utenti attualmente collegati al sistema, con l'ora in cui si sono collegati, in ordine decrescente rispetto ad essa:
# who | awk '{print $5, $1}' | sort -r | awk '{print $2, $1}'

9 Comandi principali

Vediamo ora una lista delle operazioni effettuate più frequentemente da un utente medio, con una breve descrizione dei comandi usati per realizzare le operazioni in questione.

Per una descrizione più accurata e affidabile è bene consultare il manuale in linea sul proprio sistema, usando il comando man.

9.1 Il comando principale (man)

Questo è senza dubbio il comando più importante di tutti, perché apre la porta all'utilizzo avanzato di tutti gli altri. Esso infatti consente di visualizzare e scorrere le pagine e le sezioni del manuale in linea di UNIX, che illustra in dettaglio l'uso di tutti i comandi di sistema, dai più semplici e frequentemente usati a quelli di uso più raro e complesso.

Saper utilizzare il comando man consente di risparmiare tempo e fatica, nonché di disporre di informazioni dettagliate e affidabili sull'uso dei comandi offerti dal sistema che si sta utilizzando. In definitiva è l'unica guida veramente affidabile.

Molti programmi e applicativi complessi, non facenti parte dei normali sistemi UNIX, ma comunque molto diffusi, sono forniti di manuali compatibili con man. Questo rende ancora più importante acquisire familiarità con questo comando.

La sintassi è molto semplice: nella maggior parte dei casi basta scrivere

# man comando
per veder apparire sul video le istruzioni relative a comando. Con l'opzione "-k", il comando man equivale al comando apropos, che elenca tutti i comandi che hanno una qualche relazione con comando, come nell'esempio seguente:
# apropos what
what		what (1)	- extract SCCS version information from a file
whatis		whatis (1)	- display a one-line summary about a keyword
whodo		whodo (1m)	- who is doing what
what		what (1)	- extract SCCS version information from a file
whatis		whatis (1)	- display a one-line summary about a keyword
whodo		whodo (1m)	- who is doing what
A volte però apropos è troppo prolisso, perché presenta anche delle righe in cui semplicemente appare la parola cercata, ma come parola della lingua inglese; conviene allora usare il comando whatis, che ha un campo di ricerca più limitato:
# whatis what
what		what (1)	- extract SCCS version information from a file
what		what (1)	- extract SCCS version information from a file
Si noti che, nella seconda colonna dell'output dei comandi sopra, le parole sono seguite da un numero fra parentesi, a volte seguito da una "m". In questo modo si indicano le sezioni in cui il manuale UNIX è organizzato. Ad esempio, la sezione 1 è quella di solito più consultata perché contiene i comandi più comunemente usati dagli utenti. La sezione 1m contiene invece i comandi usati dall'amministratore, in genere non utilizzabili dagli utenti normali. La sezione l contiene pagine di manuale locali, cioè relative a programmi non facenti parte di un sistema UNIX standard, ma comunque installati sul sistema. A volte però le pagine di manuale relative a simili programmi vengono inserite nella sezione n.

A volte man afferma di non aver trovato una voce nel manuale relativa a un certo comando:

# man top
No manual entry for top.
Per essere sicuri che davvero non ci siano istruzioni per il comando in esame, è sempre meglio usare whatis e poi di nuovo man, specificando però esplicitamente, con l'opzione "-s", la sezione del manuale in cui, secondo whatis, dovrebbe trovarsi il manuale del comando (ammesso che whatis riesca a trovarlo).
# whatis top
top		top (1) 	- display and update information about the top cpu processes
top		top (1/X)	- display and update information about the top cpu processes
# man -s1 top
TOP(1)                    User Commands                    TOP(1)
 
  
   
NAME
     top - display and  update  information  about  the  top  cpu
     processes
 
SYNOPSIS
     top [ -SbiInqu ] [ -dcount ] [ -stime ] [ - ofield  ]  [   -
     Uusername ] [ number ]
 
DESCRIPTION
     Top displays the top 15 processes on the system and periodi-
     cally  updates this information.  Raw cpu percentage is used
     to rank the processes.  If number is  given,  then  the  top
     number processes will be displayed instead of the default.

... 

     As with ps(1), things can change  while  top  is  collecting
     information  for  an update.  The picture it gives is only a
     close approximation to reality.
 
SEE ALSO
     kill(1), ps(1), stty(1), mem(4), renice(8)
 
...
L'esempio sopra illustra l'inizio e la fine di una tipica pagina del manuale UNIX. Si noti come, nella parte finale, siano proposti riferimenti ad'altre pagine del manuale che può essere utile consultare. In genere è un'ottima idea esaminare qualcuna di queste pagine, magari solo con whatis, perché possono offrire una soluzione insospettata a un qualche problema.

9.2 Elencare file e directory (ls)

Con il comando ls viene visualizzato l'elenco dei file presenti nella directory corrente. In genere vengono indicati solo i nomi, in più colonne, senza altre indicazioni. Con l'opzione "-l" si ha invece una lista completa, come la seguente:

total 338
-rw-r--r--   1 giuliano nobody       229 May  8 14:13 Makefile
drwxr-xr-x   2 giuliano nobody       512 May  8 14:11 RCS
-rwxrwxrwx   1 giuliano nobody     33610 May  8 14:13 csun.html
-rw-r--r--   1 giuliano nobody     32221 May  8 14:13 csun.m4
-rw-r--r--   1 giuliano nobody       947 May  8 14:41 html.m4
-rw-r--r--   1 giuliano nobody      1550 Apr 29 14:30 macros.m4
-rw-------   1 giuliano nobody      2825 Nov 21 09:24 sun.html
-rw-r--r--   1 giuliano nobody     17334 May 11 12:09 unix.html
-rw-r--r--   1 giuliano nobody     18041 May 12 11:58 unix.m4

Ogni riga è suddivisa nei seguenti campi:

Un'altra opzione interessante è -a, che visualizza anche i file nascosti, cioè quelli il cui nome inizia con "." (punto finale).

9.3 Visualizzare e cambiare la directory corrente (pwd, cd)

Per sapere qual'è la directory corrente, cioè quella su cui intervengono di norma i comandi di manipolazione dei file, si usa il comando pwd. Per spostarsi in un'altra directory si usa invece il comando cd, seguito dal nome della directory. Questo nome può essere assoluto, e allora comincia con "/", oppure relativo.

Ci sono abbreviazioni per indicare alcune directory importanti:

9.4 Creare una directory (mkdir)

Il comando mkdir crea una directory. Richiede un solo argomento, dato dal percorso completo (relativo o assoluto) della directory da creare. Ad esempio, il comando

mkdir nuova_dir
crea la nuova directory nuova_dir all'interno della directory corrente. Invece il comando
mkdir ../roberta/nuova_dir
crea ancora una directory dal nome nuova_dir, ma in una sorella della directory corrente di nome roberta. Infine, il comando
mkdir /franca/carla/nuova_dir
crea una directory ancora di nome nuova_dir, ma indica la posizione dove crearla in modo assoluto invece che relativo, come avviene invece nel comando precedente.

Un'opzione a volte molto utile è -p: essa crea eventuali sottodirectory mancanti nel file system, ma indicate nell'argomento. Ad esempio, se la directory /franca/genoveffa non esiste, il comando

mkdir -p /franca/genoveffa/teodolinda/olimpia
creerà genoveffa sotto /franca, teodolinda sotto /franca/genoveffa, e infine olimpia sotto /franca/genoveffa/teodolinda.

9.5 Copiare file e directory (cp)

Il comando cp consente di copiare file sia all'interno della directory corrente, sia da una directory ad un'altra. Richiede due argomenti obbligatori, la sorgente e la destinazione, che possono essere nomi assoluti o relativi.

Un'opzione molto utile è -i che chiede conferma della copia se la destinazione esiste già. Questo consente di limitare l'eventualità di copiare sulla destinazione sbagliata, quando questa è un file, perché in tal caso il contenuto del file destinazione è definitivamente perso, sostituito dal contenuto del file sorgente.

Un'altra opzione utile è -r che, quando la sorgente è una directory, copia il suo intero contenuto, comprese tutte le sue sottodirectory, nella destinazione, che sarà necessariamente una directory. Quest'ultima viene creata se non esiste.

9.6 Rinominare e spostare file e directory (mv)

Il comando mv è in fondo molto simile a cp, ma con una differenza importante: dopo la copia, la sorgente viene rimossa, sia essa un file o una directory. Il risultato è dunque uno spostamento oppure una rinomina.

9.7 Eliminare e spostare file e directory (rm, rmdir)

Il comando rm elimina un file o una directory, senza alcuna possibilità di recupero in caso di errori. Per questo è sempre consigliabile, anche se scomodo, usare sempre l'opzione "-i", che chiede conferma per ogni file da cancellare.
Con l'opzione "-r" si cancellano interi alberi di directory, e quindi va usata con estrema cautela. In abbinamento con l'opzione "-i" viene comunque richiesta la conferma dell'eliminazione di ogni file contenuto nell'albero specificato.
Se una directory è vuota (nel senso che non contiene file, ma neanche sottodirectory), può essere rimossa col comando rmdir. Usato su una directory non vuota esso non effettua l'eliminazione e produce un messaggio d'errore.

9.8 Creare dei link (ln)

Il comando ln serve per creare dei link a dei file o directory. Viene usato quasi sempre con l'opzione "-s", che indica che il link creato è simbolico: in altre parole, il link creato è solo un sinonimo del file o della directory a cui fa riferimento. I link non simbolici, detti anche hard link, vanno al di là degli scopi di questo documento, ma sono comunque di scarsa utilità per l'utente medio.

La sintassi è la seguente:

ln -s target link
essendo target un percorso relativo o assoluto a un file o a una directory esistenti, e link il sinonimo che si vuole definire. Anch'esso può essere un percorso relativo o assoluto, ma l'opzione "-s" fa sì che il link non possa essere un percorso già esistente, nel qual caso viene emesso un messaggio di errore in proposito.

Poiché il comando ln risulta alquanto ostico per molti utenti, vediamo qualche esempio.

Con la riga seguente si crea, nella directory corrente, un file pluto che è un link simbolico al file pippo:

ln -s pippo pluto
Un successivo comando ls -l mostrerà, fra le altre, una riga simile a quella seguente:
lrwxrwxrwx   1 giuliano users          5 Jan  8 16:11 pluto -> pippo
che indica in modo molto espressivo che pluto punta a pippo. Si noti la "l" in prima colonna, che indica appunto che il file in questione è un link.
La riga seguente crea, nella directory corrente, un link simbolico di nome glarf al file xpdf che si trova invece in una directory del tutto diversa, indicata con un percorso assoluto
ln -s /usr/local/bin/xpdf glarf
La verifica col comando ls -l | grep glarf mostrerà la riga seguente:
lrwxrwxrwx   1 giuliano users         19 Jan  8 16:14 glarf -> /usr/local/bin/xpdf
Un tipico errore che si commette col comando ln consiste nello scambiare il link con il target senza usare l'opzione "-s": il risultato è l'impossibilità di accedere al target originale. Se ad esempio esistono già i due file pluto e pippo, e si digita il comando:
ln pippo pluto
in genere non viene dato alcun messaggio di errore, ma il file pluto è ora del tutto identico al file pippo, e il suo contenuto originario è andato perduto per sempre. Con l'opzione "-s", in questa situazione, il sistema, in genere, non esegue il comando, avvertendo l'utente che il file pluto esiste già.

10 Manipolazione avanzati di file e directory

I comandi principali per la gestione dei file rappresentano il minimo indispensabile per iniziare a lavorare in ambiente UNIX. Ma non si va molto lontano limitandosi ad essi. Fra i comandi che consentono di aumentare la produttività individuale (oppure a guadagnare tempo libero) ci sono senz'altro i comandi discussi in questo paragrafo, destinati alla manipolazione avanzata di file e directory.

10.1 Concatenare e suddividere dei file (cat, split)

Può capitare, a volte, di iniziare un lavoro (la stesura di un programma, di un articolo, o altro) creando non un singolo file, ma alcuni file più piccoli, con l'idea (tutt'altro che errata) di lavorare più comodamente su queste parti, più facilmente controllabili, piuttosto che su un unico grande file. Ad esempio, un utente potrebbe organizzare gli indirizzi di posta elettronica delle persone con cui è in contatto in diversi indirizzari, divisi secondo qualche criterio.

Ma, ad un dato momento, egli si rende conto che gli converebbe non disperdere troppo questi indirizzi, e averli tutti in un solo indirizzario, magari ordinati alfabeticamente e senza ripetizioni (che potrebbero esserci se uno stesso indirizzo è stato inserito in più di un indirizzario).

A questo punto l'utente deve concatenare i file che contengono i suoi indirizzari, e per far questo userà il comando cat, la cui sintassi, almeno nel caso in esame, è la seguente:

cat file_1 file_2 ... file_n > target
In questa riga di comando, file_1,... file_n rappresentano dei file qualsiasi (nel nostro esempio, i singoli indirizzari dell'utente), mentre target è il file che conterrà l'unione di essi, uno dopo l'altro (l'indirizzario generale). È importante ricordare che i file sono sequenze di byte, e quando vengono concatenati con cat nessuno di questi byte viene alterato, né vengono aggiunti altri byte. Semplicemente, le varie sequenze vengono assemblate l'una dopo l'altra a formare un'unica sequenza. Ovviamente la lunghezza del file target è esattamente uguale alla somma delle lunghezze dei singoli file_i.

Per completare l'esempio dell'indirizzario, immaginando, per semplicità, che l'utente abbia solo due indirizzari, denominati amici e clienti, contenenti, rispettivamente, solo le poche righe seguenti

giorgia@ciccio.labour.com
diego@cucu.glarf.de
lamberto@zappa.gaga.ch
mail@laterizi.spa.it
support@dmc.condotte.it
pr@autocentro.srl.it
il comando
# cat amici clienti > tutti
produrrà un file chiamato tutti e contenente le righe seguenti:
giorgia@ciccio.labour.com
diego@cucu.glarf.de
lamberto@zappa.gaga.ch
mail@laterizi.spa.it
support@dmc.condotte.it
pr@autocentro.srl.it

Non meno importante della concatenazione dei file può rivelarsi la suddivisione di un unico file in parti più piccole. Questa esigenza si presenta ad esempio quando un file molto grande deve essere copiato su una serie di dischetti, per poter essere poi trasferito su un altro sistema e ivi ricomposto (appunto con cat).

A questa esigenza risponde il comando split. Esso scompone lo standard output in tante parti di uguale lunghezza fissata dall'utente (salvo un resto di lunghezza minore), e salva queste parti in altrettanti file con nomi opportuni. La lunghezza dei file creati, espressa in byte, è determinata dall'opzione "-b". La lunghezza può anche essere espressa in kilobyte o in megabyte, aggiungendo una "k" o una "m" dopo il numero che indica la lunghezza nell'opzione "-b".

In certi casi, se si lavora con dei file di testo, può essere più utile suddividere il file in parti contenenti lo stesso numero di righe. A questo scopo basta indicare il numero di righe richiesto preceduto dal trattino "-".

I nomi usati per i file creati sono, in mancanza di indicazioni diverse, del tipo seguente:

xaa
xab
xac
...
xba
xbb
xbc
...
In genere non c'è ragione di usare nomi diversi, ma se necessario si possono ottenere nomi costituiti da un prefisso comune a tutte le componenti generate e da un suffisso, composto da un fissato numero di lettere, che serve invece a distinguere le componenti. La lunghezza del suffisso è impostata con l'opzione "-a", mentre il prefisso va indicato dopo il nome del file da scomporre, che in questo caso è obbligatorio. Ad esempio, la riga
# split -b1400k -a1 sorgente prefisso-
scompone il file sorgente in parti di 1400 kylobyte di lunghezza ciascuna (resto a parte), che saranno denominate
prefisso-a
prefisso-b
prefisso-c
...

10.2 Filtrare righe in file di testo (grep)

Per sapere se un file contiene o meno una parola, una frase, o un'espressione più complessa, si può usare il comando grep. Il nome è derivato da Global Regular Expression Print, e sta ad indicare in modo alquanto criptico la sua funzione: visualizzare (Print) tutte (Global) le righe di un file contenenti una particolare espressione (Regular Expression).

Le espressioni regolari sono uno strumento complesso ma sorprendentemente, che sarà discusso in dettaglio più avanti. Per il momento basti sapere che l'insieme delle espressioni regolari contiene quello delle parole, delle frasi e delle espressioni alfanumeriche.

Come esempio, consideriamo di nuovo i due indirizzari di cui sopra. Essi potrebbero contenere ben più di tre righe ciascuno, e scoprire in quale dei due si trova il nome di una certa persona può essere scomodo: non c'è che da leggere entrambi i file finchè non si trova la parola cercata.

Il comando grep offre una rapida scorciatoia: la sintassi più semplice è:

grep parola file_1 file_2 ... file_n
Nel nostro esempio, se la parola da cercare è cucu, il comando
# grep cucu amici clienti
produrrà la riga seguente
amici:diego@cucu.glarf.de
Questa riga indica che la parola cercata è stata trovata nel file amici, e precisamente nella riga riportata per intero dopo i due punti. Quando si indica a grep un solo file, ovviamente vengono visualizzate solo le righe che contengono l'espressione cercata, senza indicare il nome del file che le contiene. Molto utile in certi casi è l'opzione "-v", che indica a grep di visualizzare solo le linee che non contengono l'espressione specificata. Un'altra opzione utile è "-w", che indica a grep di visualizzare solo le linee che contengono l'espressione specificata solo se non si trova all'interno di un'espressione. Ad esempio:
# grep -w "dire" testo
visualizzerà una riga con la frase "tra il dire e il fare...", ma non visualizzerà una riga con la frase "cosa direbbe...".

10.3 Tagliare e incollare colonne di testo (cut, paste)

Molti comandi UNIX, ma anche i programmi scritti dall'utente, producono dati organizzati in righe e colonne. Si pensi ad esempio a un programma che risolve numericamente un'equazione a derivate parziali la cui soluzione è una funzione reale di variabile reale. Tale soluzione si può salvare in un file, per ulteriori elaborazioni, come sequenza di righe contenenti ciascuna l'ascissa di un punto e il valore della soluzione in esso:

# cat results
0.0000000000000000e+00	3.0000000000000000e+00
4.0000000000000001e-03	2.9893158120280918e+00
8.0000000000000002e-03	2.9786885371858385e+00
1.2000000000000000e-02	2.9681795310548753e+00

...                     ...

9.7999999999999998e-01	2.9166605328200661e+00
9.8399999999999999e-01	2.9150863814809336e+00
9.8799999999999999e-01	2.9556517072798911e+00
9.9199999999999999e-01	2.9576224718575888e+00
9.9600000000000000e-01	2.9959305734945456e+00
1.0000000000000000e+00	3.0000000000000000e+00
Ma supponiamo di aver bisogno solo dei valori della funzione, ad esempio per farne una media aritmetica usando qualche altro programma. Per estrarre solo la seconda colonna del file results basta il comando
# cut -f2 results
che invia allo standard output le righe
3.0000000000000000e+00
2.9893158120280918e+00
2.9786885371858385e+00
2.9681795310548753e+00

...

2.9166605328200661e+00
2.9150863814809336e+00
2.9556517072798911e+00
2.9576224718575888e+00
2.9959305734945456e+00
3.0000000000000000e+00
L'opzione "-f" serve a specificare quali colonne devono essere estratte. Le colonne devono essere indicate come numeri interi crescenti (a partire da 1) separati da virgole e senza spazi, come in "-f2". Gruppi contigui di colonne si indicano per brevità con il numero della colonna iniziale e quello della colonna finale separati dal trattino, come in "-f3-6", che estrae tutte le colonne dalla terza alla sesta comprese. Le due sintassi si possono combinare fra loro, come in "-f1", che estrae la prima colonna e poi tutte quelle dalla terza alla quinta comprese. L'ordine delle colonne va comunque rispettato. È importante capire che cut ha bisogno di un carattere particolare per distinguere una colonna dall'altra. Questo carattere separatore è il carattere di tabulazione, inserito tramite l'opportuno tasto presente su tutte le tastiere, oppure dal programma che ha generato il file. Ma ci sono casi in cui il separatore può essere un altro simbolo:
# ypcat passwd | grep -v home | grep -v "^root"
smtp:NP:0:0:Mail Daemon User:/:
adm:NP:4:4:Admin:/var/adm:
daemon:NP:1:1::/:
nobody:NP:60001:60001:Nobody:/:
nuucp:NP:9:9:uucp Admin:/var/spool/uucppublic:/usr/lib/uucp/uucico
nobody4:NP:65534:65534:SunOS 4.x Nobody:/:
listen:*LK*:37:4:Network Admin:/usr/net/nls:
uucp:NP:5:5:uucp Admin:/usr/lib/uucp:
bin:NP:2:2::/usr/bin:
Il comando sopra estrae le informazioni relative a tutti gli utenti, filtra solo le linee che non contengono la parola home, e fra queste, infine, filtra solo le linee che non contengono la parola root. L'output del comando sopra è diviso in colonne (di diversa lunghezza) dal carattere ":". Per estrarre solo la prima colonna, e inviarla allo standard output, occorre modificare il comando così:
# ypcat passwd | grep -v home | grep -v "^root" | cut -d':' -f1
smtp
adm
daemon
nobody
nuucp
nobody4
listen
uucp
bin

10.4 Ordinare un file di testo (sort, uniq)

Molti sono i casi in cui è necessario ordinare dei dati. Ad esempio, se si vuole l'elenco degli utenti del sistema in ordine alfabetico (magari per inviare poi a ciascuno di essi un messaggio), si può usare il comando

ypcat passwd | grep -v home | cut -d':' -f1 | sort
aletti
angelo
anker
barioffi
belletti
bellinge
brandoli
burger
...
Il comando sort ordina alfabeticamente in senso crescente lo standard input, oppure il file eventualmente indicato come parametro sulla riga di comando. Si presume che esso sia diviso in righe. Con opportune opzioni, sort può essere usato per ordinare anche liste di numeri, magari a partire da una certa colonna piuttosto che dalla prima, e anche in senso descrescente invece che crescente. Ad esempio, se si vuole sapere quali sono i dieci file o directory che occupano più spazio nella propria home directory si può usare il comando
# du -sk ~/* | sort -rn | head
5834	/home/sempronio/mail
2991	/home/sempronio/public_html
2399	/home/sempronio/img
1448	/home/sempronio/bootdsk
1282	/home/sempronio/docs
1154	/home/sempronio/prj
600	/home/sempronio/rc5des
453	/home/sempronio/var
328	/home/sempronio/ric1.jpg
296	/home/sempronio/EuroCalc.exe
In questo esempio, il comando du -sk ~/* indica lo spazio occupato nella home directory da ogni file e directory, ordinando il risultato in base ai nomi in senso crescente. Ma poichè ci interessa, in questo caso, ordinare questo elenco in base allo spazio occupato, esso viene filtrato con sort. L'opzione "-r" indica che il risultato deve essere presentato in senso decrescente, mentre l'opzione "-n" indica che l'ordinamento non dev'essere alfabetico, ma numerico. C'è una notevole differenza: se non avessimo usato tale opzione, il risultato sarebbe stato
# du -sk ~/* | sort -r | head
600     /home/sempronio/rc5des
5834    /home/sempronio/mail
453     /home/sempronio/var
328     /home/sempronio/ric1.jpg
2991    /home/sempronio/public_html
296     /home/sempronio/EuroCalc.exe
2399    /home/sempronio/img
1448    /home/sempronio/bootdsk
1282    /home/sempronio/docs
1154    /home/sempronio/prj
Infatti, in ordine alfabetico, le cifre sono considerate come qualsiasi altro simbolo. Pertanto, sebbene 600 sia numericamente minore di 5834, dal punto di vista alfabetico è maggiore, perchè inizia con 6 che è maggiore di 5.

10.5 Cercare file e directory (find)

Non è raro trovarsi nella necessità di cercare, nel proprio albero di directory o anche fuori di esso, uno o più file o directory che verificano una certa condizione. Ad esempio, l'utente che si volesse fare spazio nel suo account, eliminando file che non usa più da molto tempo, potrebbe scoprire quali sono usando il comando find nel modo seguente:

# find ~ -atime +30 
/home/sempronio/docs/java/Java.ps.gz
/home/sempronio/docs/java/Java1.ps.gz
/home/sempronio/docs/java/Java2.ps.gz
/home/sempronio/docs/java/Java3.ps.gz
/home/sempronio/docs/java/Java4.ps.gz
/home/sempronio/docs/java/Java5.ps.gz
/home/sempronio/docs/java/Java6.ps.gz
/home/sempronio/docs/java/Java7.ps.gz
/home/sempronio/docs/java/beans.101.ps.gz
...
I file così elencati sono stati aperti (cioè letti o comunque utilizzati) almeno 30 giorni fa. Sono dei buoni candidati ad essere eliminati, anche se è meglio verificare caso per caso. Il comando find ha una gran quantità di opzioni, che consentono di selezionare i file da cercare in base a moltissime condizioni. Ad esempio, modificando opportunamente il comando visto sopra, si può limitare l'attenzione ai file che, oltre ad essere stati aperti più di 30 giorni fa, hanno anche una lunghezza di almeno 10000 byte, e che quindi occupato più spazio:
# find ~ -atime +30 -size +10000c
/home/sempronio/docs/java/Java.ps.gz
/home/sempronio/docs/java/beans.101.ps.gz
Il simbolo "+" usato davanti a un numero in certe opzioni significa che il valore per un il relativo parametro deve essere superiore al numero indicato. Il segno "-" indica invece che tale valore deve essere inferiore al numero indicato. Per questo, nell'esempio sopra, se si usasse questo segno si otterrebbe un risultato completamente diverso: verrebbero elencati i file lunghi al massimo 10000 byte e aperti almeno una volta negli ultimi 30 giorni. Un'opzione molto sofisticata, da usare con cautela, è "-exec". Essa consente di eseguire un comando su ogni file o directory corrispondente alle condizioni impostate. Il problema è che se queste condizioni non sono state impostate con la chiara consapevolezza del loro significato, il comando scelto potrebbe essere eseguito anche su file e directory che dovrebbero invece rimanere come sono, e che non sarà poi possibile, in genere, riportare al loro stato originale! !@#