La shell BASH11.1 I comandiLa shell e' un interprete di comandi. I comandi digitati dall'utente vengono letti dalla shell, interpretati e inviati al kernel per essere eseguiti. La shell e' percio' una interfaccia per gli umani, cioe' un programma che accetta i comandi digitati dall'utente, li trasforma in istruzioni eseguibili dal computer e li invia al kernel per l'esecuzione. Supponiamo di voler intrattenere una conversazione con una persona straniera, ad esempio un norvegese: conoscendo la lingua, non avremmo problemi, in caso contrario avremmo bisogno di un interprete, cioe' di una persona che, conoscendo entrambe le lingue possa tradurre da una lingua all'altra e viceversa. La shell e' qualcosa di simile: converte i nostri comandi in istruzioni eseguibili dalla macchina. I comandi vengono digitati dall'utente sulla riga comandi della shell. La riga comandi e' una riga digitabile che comincia dal prompt. Il prompt e' un carattere o un insieme di caratteri che possono essere personalizzati dall'utente. Il prompt dell'utente root (il superuser) inizia con il carattere '#' (cancelletto), mentre il prompt di un utente qualsiasi inizia con il carattere '$' (dollaro). Ecco un esempio di prompt: mau@localhost mau]$_ il carattere di sottolineatura '_' (underscore) rappresenta il cursore dal quale e' possibile iniziare a scrivere. Ma un prompt come questo appena visto puo' essere personalizzato modificando la variabile PS1 presente nel file di configurazione .bash_profile. Ad esempio si potrebbe definire un prompt di questo tipo: sto aspettando un tuo comando:_ I comandi sono dei programmi che sono contenuti all'interno di alcune directory speciali come le directory /bin e /sbin. Quando l'utente digita il nome del comando/programma e preme il tasto invio, la shell cerca tale file in alcune directory predefinite (come /bin e /sbin appunto) e se lo trova lo esegue. In caso contrario produce un errore del tipo bash: nome-comando : command not found
cioe' comando non trovato. Un comando e' composto dal nome del comando stesso, da una o piu' opzioni facoltative e da uno o piu' argomenti
facoltativi. Un argomento e' solitamente il nome di un file sul quale il comando deve agire. Alcuni comandi prevedono
degli argomenti obbligatori, altri no:
nome-comando -opzione argomento
il nome del comando deve essere separato dalle opzioni da uno spazio, cosi' come le opzioni e gli eventuali argomenti.
Le opzioni sono specificate usando un trattino '-' e la lettera o le lettere che specificano le opzioni. L'ordine e':
1) nome-comando, spazio, 2) -opzioni, spazio, 3) argomenti. Tra il trattino ed i caratteri di opzione non devono essere
presenti spazi. Ad esempio il comando ls consente l'uso di alcune opzioni come l (lista estesa) a (tutti i file)
i (visualizza inode) e via dicendo. Percio' per visualizzare l'elenco dei file di una directory si puo' usare il comando
'ls -lai'. Se si vogliono visualizzare le informazioni di un file ben preciso, occorre specificare il nome del file come
argomento. Ad esempio con il comando 'ls -l pippo' vengono visualizzate le informazioni sul file pippo.
Ecco alcuni esempi dello stesso comando, alcuni errati ed alcuni corretti:
ls -lai (corretto)
un esempio di comando che puo' accettare piu' argomenti e' il comando cp (CoPy, cioe' copia) che consente
di effettuare la copia di un file in un altro file con un nome diverso. Questo comando puo' essere utile
se si possiede un documento importante e si desidera salvarlo in una directory di salvataggio. Qualora
il file originario venisse cancellato accidentalmente, si avrebbe sempre a disposizione la sua copia
nella directory di salvataggio. Percio' si puo' usare il comando cp specificando il file da copiare
ed il nome della nuova copia dello stesso file. Ad esempio:
cp documento /home/mau/salvataggi/documento.bak
come si puo' vedere il primo argomento del comando cp e' 'documento' mentre il secondo argomento e'
'/home/mau/salvataggi/documento.bak'. In questo comando non sono presenti opzioni poiche' non
e' presente un carattere '-' che contraddistingue le opzioni. Le opzioni infatti, per definizione
sono facoltative. Nel primo argomento non e' stato specificato il path completo,
cioe' il percorso per raggiungere il file documento. In questo caso la shell sa di dover reperire
tale file dalla directory corrente. Per default infatti se non si specifica un path, la shell
cerca il file nella directory corrente (chiamata anche directory di lavoro). Nel secondo argomento invece
e' stato specificato il path completo, perche' altrimenti la shell avrebbe copiato il file documento
nella directory corrente con il nome documento.bak. Cio' sarebbe stato possibile, ma il nostro
obiettivo e' quello di salvarlo in una directory diversa e preposta al salvataggio dei nostri documenti.
Ad ogni modo il comando 'cp documento documento.bak' e' un comando perfettamente legale in quanto i due
argomenti hanno nomi diversi. Non si puo' dire altrettanto del comando: 'cp documento documento',
in quanto il nome del file iniziale e quello della copia sono identici.
In questo caso infatti riceveremmo un messaggio di errore della shell che ci informa
che il file documento esiste gia'. Non e' possibile infatti avere due file diversi con lo stesso nome
all'interno della stessa directory. Se per assurdo cio' fosse possibile, nel caso si volesse visualizzare
il file documento, quale dei due file dovrebbe aprire la shell? Al contrario due file con lo stesso nome
possono esistere nel sistema purche' residenti in due directory distinte. Nell'esempio sopra avremmo
potuto percio' scrivere:
cp documento /home/mau/salvataggi/documento
ora i due argomenti hanno lo stesso nome (documento) ma questo comando e' perfettamente legale e la shell lo
interpretera' senza problemi. Questo perche' i due file pur avendo lo stesso nome risiedono in directory diverse.
Non esiste percio' ambiguita' in questo caso, purche' per referenziare uno dei due file venga specificato il path completo.
Nell'esempio la directory che contiene il file originale e' quella corrente cioe' /home/mau/ e per referenziare
il file originale occorre scrivere /home/mau/documento; la copia di tale file invece risiede nella directory di salvataggio
/home/mau/salvataggi pertanto per referenziarla occorre scrivere /home/mau/salvataggi/documento. Per lavorare
con i file e' necessario conoscere alcuni comandi basilari come cp, mv, rm ed altri: cio' sara' oggetto di un
successivo capitolo. E' possibile digitare piu' comandi sulla stessa riga comando separandoli con il carattere ';'.
E' anche possibile scrivere dei comandi molto lunghi su piu' righe usando il carattere '\' a fine riga. In questo caso,
premendo invio si potra' scrivere su una nuova riga per continuare la digitazione del comando, ma niente verra' inviato
alla shell. Ogni riga che termina con '\' ed il tasto invio, crea una nuova riga ma non permette di eseguire il comando.
Per eseguire il comando occorrera' premere invio avendo l'accortezza di non terminare il comando stesso con il carattere
'\'. Ad esempio:
questo e' un comando molto lungo \ (premo invio)
In pratica il carattere \ dice alla shell: 'in questa riga il tasto invio non serve per inviarti il comando ma per andare a capo'.
Il tasto \ e' in questo caso un metacarattere, cioe' un carattere che maschera un altro carattere.
Il tasto invio infatti produce un carattere di 'new line' che la shell interpreta come fine del comando. Mascherando
tale carattere con il metacarattere \ potremo andare a capo ma la shell non lo considerera' come carattere di fine comando.
All'ultima riga, alla fine del comando, premendo invio senza \ faremo eseguire il comando alla shell.
Infine un ultimo quesito: come interrompere un comando che sta impiegando troppo tempo? Premendo la
combinazione di tasti CTRL-C. Tale combinazione di tasti infatti interrompe l'esecuzione di qualsiasi comando.
I sistemi operativi che esistevano prima di Linux e di Unix (ricordiamo che Linux
e' un clone di Unix) possedevano gia' degli interpreti di comandi al loro interno, ma tali interpreti avevano un difetto:
non erano modificabili. Quando Ken Thompson e Dennis Ritchie cominciarono a scrivere Unix, decisero di creare una
interfaccia utente modificabile a seconda delle esigenze che si potevano presentare di volta in volta. Cio' che venne
fuori fu un tipo di shell programmabile, contenente istruzioni simili a quelle del linguaggio C. Questo non e' un caso
visto che la prima versione di Unix venne scritta in linguaggio assembler, ma fu successivamente riscritta in linguaggio
C (ricordiamo che Dennis Ritchie e' insieme a Brian Kerninghan l'inventore del linguaggio C).
L'interprete dei comandi creato sotto Unix venne chiamato shell. Una delle prime shell venne creata agli inizi degli anni 70 presso i Bell
Laboratories AT&T ad opera di Steven R. Bourne e venne chiamata appunto Bourne shell (sh). Verso la fine degli anni 70
presso l'universita' di Berkley venne creata la C shell (csh) allo scopo di estendere la shell Bourne e renderla piu' simile
al linguaggio di programmazione C. Successivamente vennero sviluppate altre shell, come la Korn shell (ksh) e la TC shell (tcsh).
A causa dei problemi di copyright, l'organizzazione GNU decise di sviluppare una shell completamente libera da restrizioni
e nacque cosi' la shell BASH, cioe' Bourne Again SHell. Esistono molteplici versioni di shell,
la shell ash, la shell csh, la shell ksh, la shell pdksh, la shell tcsh, la shell zsh ed altre ancora, ma la shell BASH e'
senza dubbio la piu' famosa ed usata in tutti i sistemi Linux. La shell BASH e' conforme allo standard POSIX. Posix sta
per Portable Operating System Interface for uniX, cioe' interfaccia standard per il sistema operativo Unix e si tratta di
uno standard creato verso la fine degli anni 80 allo scopo di uniformare le varie versioni di Unix.
Successivamente, ad opera del gruppo IEEE (Institute of Electrical and Electronics Engineers, cioe' istituto degli ingegneri
elettrotecnici ed elettronici) lo standard POSIX venne adottato anche da altri sistemi operativi non Unix come VMS, MVS, NT etc.
Per iniziare ad esplorare la shell BASH e' sufficiente disporre di un emulatore di terminale.
Se stiamo lavorando in ambiente grafico (X Window) occorre aprire una finestra di emulazione terminale come ad esempio Xterm,
altrimenti non occorre fare nulla, in quanto ci troviamo gia' in modalita' terminale. Nel primo caso, supponendo di usare un desktop
grafico come KDE, bastera' cliccare sul bottone di avvio di KDE, selezionare 'terminali' e scegliere il tipo di terminale che si preferisce.
A questo punto ci si trova all'interno di una shell, che potrebbe essere BASH o CSH o TCSH o altro. Normalmente pero' la shell di default,
cioe' quella preimpostata inizialmente e' la shell BASH. Ad ogni modo e' sempre possibile invocare la shell BASH digitando il comando
'sh' oppure il comando 'bash'. Questo comando non fa altro che invocare la shell BASH. Piu' esattamente invoca una subshell, ossia una shell
BASH all'interno della shell corrente. Per uscire dalla subshell e' possibile digitare il comando 'exit' o premere i tasti CTRL-D (Ctrl e
D contemporaneamente). Premendo CTRL-D da una subshell si ritorna alla shell corrente e premendo nuovamente CTRL-D si esce dalla shell
iniziale. Per scoprire quali shell siano installate nel nostro sistema, e' possibile visualizzare il file /etc/shells utilizzando il
comando:
cat /etc/shells
verra' visualizzato un elenco delle shell disponibili. Per invocare una qualsiasi delle shell elencate e' sufficiente digitarne il nome
e premere invio. Cosi' facendo verra' creata una ISTANZA della shell digitata. E' possibile creare piu' istanze, l'una all'interno
dell'altra (a mo' di bambola matrioska), digitando il nome della shell. Per capire meglio cio', apriamo un terminale tipo Xterm e digitiamo
il comando exit (o i tasti CTRL-D): cosa accade? Si chiude la finestra Xterm e si ritorna nel desktop, poiche' il comando exit permette
di uscire dalla shell. Ora facciamo una seconda prova: apriamo la finestra Xterm e digitiamo il comando: bash. Apparentemente non accade
nulla in quanto il sistema non fa altro che riproporre il prompt visualizzando una seconda riga comandi vuota. In realta' pero' abbiamo
appena creato una subshell bash, abbiamo cioe' invocato una shell bash all'interno della shell bash iniziale. Per dimostrarlo digitiamo il
comando exit. Cosa accade? La finestra Xterm non si chiude, ed il sistema ripropone ancora il prompt. Questo avviene perche' il comando
exit distrugge la subshell che abbiamo creato e ritorna a quella iniziale. A questo punto, digitando nuovamente il comando exit si chiudera'
la finestra, in quanto usciremo anche dalla shell iniziale. Digitando il comando bash piu' volte possiamo creare innumerevoli subshell
una all'interno dell'altra. Per uscire dalla finestra Xterm percio', dovremo digitare il comando exit tante volte quante subshell abbiamo
creato. La primissima shell che Linux ci propone e' la shell di login, ossia la shell con la quale l'utente effettua il login.
Cosa e' possibile fare con una shell? Prima di tutto inviare comandi al sistema, ma e' anche possibile creare dei programmi per
effettuare operazioni particolari o per eseguire una serie di comandi in sequenza. Vediamo cosa accade digitando il comando:
ls -l *
apparentemente il sistema mostra un elenco di file e cio' appare ai nostri occhi come una operazione semplicissima. In realta', ogni volta che
viene eseguito un semplice comando, il sistema effettua tutta una serie di operazioni invisibili ai nostri occhi delle quali non sospetteremmo
minimamente l'esistenza. Nell'esempio precedente, una volta digitato il comando e premuto il tasto invio, il sistema o meglio la shell:
non male come lavoro eh? ;o) Andando avanti nella conoscenza di Linux, cominceremo ad usare la shell sempre piu' spesso, in quanto molte
volte troveremo piu' semplice digitare alcuni comandi piuttosto che cliccare a destra e a sinistra con il mouse. Prima di esaminare i
comandi principali di Linux e di imparare a programmare la shell, e' utile apprendere a districarsi all'interno della riga comando, applicando
molte scorciatoie che il sistema offre per velocizzare la digitazione dei comandi. Ad esempio e' possibile rieseguire l'ultimo comando
digitando !! e premendo invio, e' possibile visualizzare i comandi appena digitati o rieseguire un comando ben preciso premendo un solo tasto,e' possibile concatenare i comandi tra loro, e via dicendo. Tutto cio' e' oggetto del prossimo paragrafo.
Vediamo come 'navigare' all'interno della riga comando. Prima di tutto occorre conoscere lo scopo del tasto invio. Il tasto invio e' un tasto
utilizzato per comunicare al sistema: 'ok, ho appena finito di digitare il comando, puoi eseguirlo'. Una volta premuto invio il sistema viene
allertato per eseguire il comando digitato. Ogni volta che si preme un tasto, indipendentemente dal sistema operativo usato, viene attivata
una cosidetta richiesta di interrupt di tipo hardware che, molto piu' semplicemente significa che un dispositivo hardware (la tastiera
in questo caso) 'sveglia' il sistema dal torpore e gli comunica che deve intraprendere un'azione. In realta' il sistema non dorme, ma esegue
altre operazioni in sottofondo. Il sistema e' sempre in movimento ed effettua molte operazioni continuamente. Pero', ogni volta che viene
premuto un tasto invio, il sistema viene bruscamente interrotto da qualsiasi azione stava eseguendo per rispondere alla richiesta
di attenzione inviata dalla tastiera. Se ci si trova all'interno di un programma di scrittura e stiamo scrivendo una lettera, ad ogni tasto premuto il sistema risponde visualizzando il carattere corrispondente, a meno che non si tratti di un tasto speciale come ad esempio il tasto invio, il tasto canc, il tasto freccia in alto e via dicendo. All'interno di un programma di scrittura di testi il tasto invio permette di
andare a capo, mentre all'interno della riga comando serve per avvertire il sistema che ci occorre la sua attenzione per eseguire il comando
appena digitato. Ma prima di inviare il comando al sistema con il tasto invio, e' possibile editarlo (il termine editare e' uno italianismo
del termine inglese edit che sigifica modificare). Per modificare quanto si sta scrivendo sulla riga comando esistono molte possibilita'.
Ad esempio e possibile andare avanti ed indietro nella riga comandi premendo i tasti freccia a sinistra e freccia a destra. Oppure e'
possibile cancellare l'ultimo carattere appena digitato premendo il tasto canc. Ma e' anche possibile cancellare l'ultima parola appena
digitata premendo i tasti CTRL-W. Oppure e' possibile cancellare l'intera riga appena scritta premendo i tasti CTRL-U. I tasti freccia
in alto e freccia in basso invece, sono utili per scorrere la storia dei comandi. La shell infatti memorizza i comandi che vengono
digitati all'interno di un file di sistema, che e' possibile scorrere a video tramite i tasti freccia in alto e freccia in basso. Cio'
permette di eseguire gli stessi comandi piu' volte senza doverli riscrivere, oppure di visualizzare un comando precedentemente digitato
per modificarlo e rieseguirlo. I comandi eseguiti vengono memorizzati all'interno di un file di sistema che si trova all'interno della
directory home dell'utente e che si chiama .bash_history. Ad esempio l'utente mau avra' un suo file di storia dei comandi all'interno
della directory /home/mau. Per visualizzare i comandi presenti in questo file e' possibile usare il comando history. Oppure
e' possibile visualizzarlo con il comando cat. Il comando cat visualizza il contenuto di un file (in realta' lo scopo del comando cat
e' ben altro, ma per ora e' irrilevante saperlo). Ad esempio 'cat pippo' permette di visualizzare a video il contenuto del file pippo.
Quindi l'utente mau puo' visualizzare la sua storia dei comandi con il comando cat /home/mau/.bash_history. Un sistema Unix o Linux
e' un sistema multiutente, percio' nello stesso istante possono coesistere piu' utenti che lavorano con lo stesso sistema. Bene, ogni
utente ha a disposizione una directory home personale, una shell personale e ovviamente, un file di storia personale. Esistono pertanto
tante copie del file .bash_history quanti sono gli utenti che posseggono un account su un sistema. Nel caso di un sistema Linux su un PC
utilizzato da un unico utente sara' presente ovviamente una sola copia del file .bash_history. Digitando il comando
history
verra' visualizzato a video un elenco di tutti i comandi digitati. A sinistra di ciascun comando e' presente un numero progressivo che
rappresenta un identificativo utilizzabile per richiamare quel dato comando. Infatti digitando il carattere ! e premendo invio viene eseguito
l'ultimo comando appena eseguito, ma digitando il carattere ! seguito da un numero, e' possibile eseguire il comando referenziato da
quel numero. Ad esempio, se digitando history si ottiene:
1 ls
digitando il comando:
!3
viene eseguito il comando 'cat pippo' (questo comando visualizza il file pippo). Un'altra scorciatoia molto utile e' il tasto TAB.
E' possibile espandere nomi di file o di comandi digitando una serie di caratteri (pattern) e premendo TAB. Ad esempio, supponiamo
di voler eseguire il comando mount, ma non ricordiamo esattamente il nome del comando. Sappiamo solo che inizia per 'm' o per 'mo'.
Bene, digitando m e premendo TAB, il sistema visualizzera' tutti i comandi che iniziano per m. Digitando mo e premendo TAB,
il sistema visualizzera' tutti i comandi che iniziano per mo. Premendo il tasto TAB senza digitare alcun carattere il sistema
chiedera' la conferma per visualizzare tutti i comandi che conosce. La ricerca dei comandi viene effettuata scorrendo la variabile
di sistema PATH, che contiene tutte le directory dove il sistema deve ricercare i comandi da eseguire. Se si digita un comando e
successivamente alcuni caratteri e poi si premte TAB, il sistema non cerca il nome di un comando ma il nome di un file.
Ad esempio, digitando:
ls pr
e premendo TAB senza premere invio, la shell visualizzera' tutti i file che iniziano per pr come prova, provetta, prosa, prassi e via dicendo,
ed inoltre consentira' di proseguire il comando ls continuando a digitare i caratteri rimanenti. Infatti a questo punto e' possibile
digitare ls prov e premere TAB. La shell visualizzera' ora solo i file prova e provetta. E' un sistema utile quando sono presenti
centinaia di voci e non rammentiamo bene il nome esatto del comando o del file che ci interessa.
Digitare frequentemente dei comandi complessi contenenti numerose opzioni puo' essere alla lunga fastidioso, percio'
puo' esser conveniente utilizzare dei sinonimi piu' facili da ricordare e da digitare. Prendiamo ad esempio il comando:
mount -t vfat /dev/hdc1 /mnt/mydir
questo comando 'monta' la prima partizione presente sul terzo disco alla directory /mnt/mydir, specificando la tipologia
del filesystem (vfat). Supponiamo che tale partizione contenga i file di Windows: sarebbe interessante poter sostituire
tale comando con il comando 'montaWindows'. Bene, e' effettivamente possibile fare cio' creando l'alias montaWindows
per tale comando. Per creare l'alias 'montaWindows' occorre usare il comando alias:
alias montaWindows='mount -t vfat /dev/hdc1 /mnt/mydir'
questo comando non fa altro che creare il sinomimo montaWindows. Una volta eseguito questo comando, sara' possibile usare
il sinonimo creato: lanciando montaWindows verra' eseguito il comando 'mount -t vfat /dev/hdc1 /mnt/mydir'. Gli alias possono
essere utili anche per creare dei comandi in lingua italiana. Ad esempio, il comando cp si potrebbe sostituire con 'copia',
il comando rm potrebbe chiamarsi 'cancella' oppure potremmo sostituire il comando pwd con 'dovemitrovo'. Un alias puo'
essere utile anche per limitare operazioni pericolose. Ad esempio, il comando rm cancella i file irreversibilmente senza
chiedere conferma, a meno che non venga usata l'opzione -i. Pertanto, poiche' il comando rm cancella senza conferma,
mentre il comando 'rm -i' cancella chiedendo conferma, e' possibile creare un sinonimo di rm in questo modo:
alias rm='rm -i'
da questo momento in poi, digitando il comando rm il sistema chiedera' conferma prima di cancellare qualsiasi file. ;o)
Per eliminare un alias e' possibile usare il comando :
unalias rm
dove rm e' il nome dell'alias.
Per evitare di uscire dalla shell digitando inavvertitamente i tasti CTRL-D, e' possibile usare l'opzione ignoreeof.
Quest'opzione viene attivata con il comando set. Il comando set accetta due opzioni: -o e o. -o imposta ignoreeof
mentre o lo elimina. Il altre parole, per impostare l'opzione ignoreeof occorre digitare il comando:
set -o ignoreeof
mentre per ripristinare il comportamento normale della shell occorre digitare:
set o ignoreeof
Esistono altre opzioni per modificare il comportamento della shell, tra le quali noclobber e noglob. La prima
serve per evitare che un file venga cancellato inavvertitamente da una operazione di redirezione. Ad esempio il comando
'cat pippo > pluto' potrebbe sovrascrivere il contenuto di pluto con pippo. Impostando l'opzione noclobber con il comando set,
non sara' piu' possibile sovrascrivere il file pluto in quanto la shell presentera' un messaggio di errore. Vediamo:
ls > pluto (copio l'elenco dei file presenti nella directory all'interno del file pluto)
L'opzione noglob infine, disattiva i caratteri speciali della shell. Una volta impostata tale opzione i caratteri *, ?, [,
] e ~ non verranno piu' espansi se presenti all'interno di un file. Cio' puo' essere utile per fare riferimento a file che
contengono tali caratteri. Ad esempio, scrivendo 'pippo*' normalmente la shell espanderebbe pippo con tutti i nomi dei file
che iniziano con 'pippo' e terminano con una qualsiasi sequenza di caratteri: impostando l'opzione noglob, cio' non accadrebbe
piu' e sarebbe possibile far riferimento al file pippo* senza problemi. Inutile dire che e' comunque meglio evitare di creare nomi di
file contenenti caratteri speciali! ;o)
La shell BASH ha delle impostazioni standard generali per tutti gli utenti, ma ogni utente
puo' avere una versione personalizzata della propria shell modificando opportunamente
alcuni file di configurazione. All'interno di questi file sono presenti delle
variabili che contengono dei valori predefiniti. Una variabile e' un'area di memoria alla
quale viene assegnato uno specifico valore. Tale area viene creata al momento del login e viene
distrutta al momento del logout. Una variabile puo' essere paragonata ad una scatola nera che
puo' contenere dei valori. Ad esempio la variabile USER contiene il nome dell'utente che ha
effettuato il login. Quando un utente effettua il login nel sistema, Linux crea una shell
di login ed inizializza alcune variabili con dei valori predefiniti.
L'utente puo' creare delle variabili personali e puo' modificare alcune di
quelle predefinite dal sistema. Per convenzione le variabili della shell sono definite
con nomi costituiti da lettere maiuscole. Ad esempio, la variabile HOME definisce il percorso
della directory home dell'utente. Le variabili vengono inizializzate dal sistema al momento
del login da parte di un utente e vengono distrutte al momento del logout, cioe' quando
l'utente si scollega dal sistema. Per visualizzare il contenuto di una variabile si puo'
eseguire il comando echo, seguito dal carattere $ e dal nome della variabile. Ad esempio,
un ipotetico utente mau, visualizzando la variabile HOME utilizzando il comando:
echo $HOME
produrra' a video il percorso /home/mau. I file di configurazione della shell BASH sono 5:
le prime 2 sono generali per tutti gli utenti e le altre 3 sono specifiche per ogni utente
e se vengono modificate ridefiniscono quelle generali. Percio' se un utente 'mau' modifica
ad esempio il file .bash_profile presente nella sua directory home (/home/mau), tali modifiche
saranno valide per lui ma non per tutti gli altri utenti che continueranno ad usare il
file profile generale presente nella directory /etc. Stesso discorso vale per il file bashrc.
Il file profile presente nella directory /etc puo' essere paragonato al file autoexec.bat del dos.
Questo file infatti contiene l'inizializzazione di alcune variabili di sistema e l'esecuzione di alcuni
programmi di avvio. I file bashrc invece contiene gli alias ed alcune funzioni definibili dall'utente.
Un alias e' un nome mnemonico che si puo' dare ad un comando.
Ad esempio il comando che visualizza tutti i file di una directory:
ls -lai
puo' avere come alias il nome 'elencafile' oppure 'lsa' oppure 'dir' (per gli amanti del DOS) o
un qualsiasi altro nome scelto dall'utente. Un'altra differenza che contraddistingue il file
profile dal file bashrc sta nel fatto che mentre il primo viene eseguito al momento del login
da parte dell'utente, il secondo viene eseguito ogni volta che viene creata una shell o una
subshell. Quando l'utente effettua il login, viene creata una shell chiamata shell di login,
percio' viene eseguito prima il file profile e poi il file bashrc. Quando un utente crea una
subshell od una shell che non e' di login (ad esempio apre una finestra Xterm) viene
eseguito il file bashrc. In un sistema Linux, oltre ai file di inizializzazione della shell attivati
al momento del login, e' presente anche un file attivato al momento del logout. Una subshell viene
creata automaticamente dal sistema ogni volta che si esegue un comando oppure intenzionalmente
dall'utente lanciando il comando che crea la shell (che nel caso di shell BASH e' 'bash'). Ogni
volta che un utente effettua il logout e si scollega dal sistema, viene eseguito il file
.bash_logout. In questo file sono presenti tutte le operazioni di chiusura che l'utente
vuole eseguire. Questo file non viene creato automaticamente come gli altri gia' visti,
percio' occorre crearlo manualmente con un editor di testi qualsiasi (ad esempio vi).
In questo file puo' essere contenuto ad esempio un messaggio di arrivederci con un comando
tipo echo "Arrivederci". Riassumendo, non appena un utente effettua il login nel sistema:
non appena l'utente effettua il login dal sistema, viene eseguito il file .bash_logout.
Come gia' visto precedentemente per nominare un file e' possibile usare fino a 256 caratteri, pero' esiste una limitazione:
non e' possibile usare determinati caratteri. Tali caratteri infatti sono speciali, in quanto se presenti, vengono
interpretati dalla shell seguendo delle regole ben precise. Ecco un elenco di alcuni di tali caratteri:
. / " $ & ' ? ~ ! < > * = .. ; [ ]
ognuno di questi caratteri ha un significato ben preciso per la shell, ad esempio il carattere '.' significa la directory
corrente, il carattere '..' e' la directory immediatamente superiore, il carattere '~' rappresenta la directory
home, il carattere ';' e' usato per separare piu' comandi sulla stessa riga e via dicendo. I caratteri speciali che verranno
analizzati qui sono i caratteri: '*', '?' , '[' e ']'. Tali caratteri vengono definiti anche caratteri jolly o anche
wildcards. Si tratta di caratteri che vengono usati dalla shell per espandere il nome di un file.
Il carattere '*' significa qualsiasi carattere o qualsiasi sequenza di caratteri. Digitando una
serie di caratteri e terminando la serie con il carattere *, la shell individuera' tutti i file all'interno della directory
corrente i cui nomi iniziano con la serie di caratteri digitati e terminano con una sequenza qualsiasi di caratteri.
Digitando solo il carattere *, la shell individuera' semplicemente tutti i file all'interno della directory corrente.
Ad esempio, supponiamo che l'utente mau possegga all'interno della directory documenti i file lettera1, lettera2, doc,
letteratura.txt, lettere e doc2. Il comando:
ls lett*
visualizzera' solo i file lettera1, lettera2, lettere e letteratura.txt. i file doc1 e doc2 non verranno visualizzati.
Cio' perche' la shell considerera' tutti i file presenti all'interno della directory che iniziano con i caratteri
'lett' e terminano con una sequenza qualsiasi di caratteri. I file doc1 e doc2 non soddisfano tali requisiti.
Invece, digitando il comando:
ls lettera*
la shell visualizzera' i file lettera1, lettera2 e letteratura.txt. Questa volta, oltre ai file doc1 e doc2 verra' escluso
dall'elenco anche il file lettere che percio' non verra' visualizzato. Ma supponiamo ora che di tutti i file presenti
nella directory volessimo visualizzare solamente i file lettera1 e lettera2: come dovremmo usare il carattere '*'?
Bene, in questo caso scrivendo lettera* visualizzeremmo i file lettera1, lettera2 ma anche letteratura.txt. Come fare allora?
Semplice: potremmo usare il carattere '?'. Infatti il carattere ? significa qualsiasi carattere. Nel nostro esempio
pertanto potremmo scrivere il comando: 'ls lettera?'. La shell interpretera' la stringa 'lettera?' cercando all'interno
della directory corrente tutti i file il cui nome inizia per 'lettera' e termina con 1 carattere qualsiasi. La differenza
tra il carattere * ed il carattere ? sta nel fatto che mentre con il primo si intende qualsiasi sequenza di caratteri,
con il secondo si intende qualsiasi carattere. Per specificare ulteriormente i caratteri da espandere, si puo'
specificare uno o piu' caratteri all'interno di una coppia di parentesi quadre. I caratteri definiti tra parentesi quadre
stabiliscono un insieme di caratteri validi che devono essere presenti all'interno del nome dei file da considerare.
Ad esempio, supponendo di avere all'interno della directory corrente i file doc1, doc2, docA1, docB1 e doca2, specificando
la stringa doc[1A] prenderemmo in considerazione solamente i file doc1 e docA1 in quanto entrambi hanno un nome che
inizia con i caratteri doc e termina con il carattere 1 o con il carattere A. Come possiamo osservare non viene preso in
considerazione neanche il file doca2 perche' Linux e' un sistema case sensitive, cioe' fa differenza tra caratteri maiuscoli
e caratteri minuscoli. Per Linux i caratteri 'A' e 'a' sono due caratteri completamente diversi. Se avessimo voluto
prendere in considerazione anche il file doca2, avremmo dovuto scrivere doc[1Aa]. L'ordine con il quale vengono digitati
i caratteri jolly all'interno delle parentesi quadre e' ininfluente, percio' avremmo potuto scrivere anche doc[Aa1] o
doc[A1a]. Ma i caratteri jolly possono servire non solamente a specificare dei nomi di file che cominciano con una sequenza
di caratteri prestabilita e terminano con una sequenza di caratteri indefinita: infatti e' possibile anche effettuare
l'operazione inversa, cioe' specificare dei nomi di file che iniziano con una sequenza di caratteri indefinita e che
pero' terminano con dei caratteri ben precisi. Ad esempio, supponendo di avere all'interno della directory corrente i file
doc.txt, doc.doc, lettera.doc e lettera.txt, scrivendo *.doc specificheremmo solamente i file doc.doc e lettera.doc.
All'interno delle parentesi quadre e' possibile anche specificare una sequenza di valori usando il carattere '-'. Ad esempio
la stringa doc[1-9] significa qualsiasi file il cui nome inizia per doc e termina con una cifra da 1 a 9. Supponendo di avere
all'interno della nostra directory i file doc1, doc2, doc3, doc4 e doc5, scrivendo la stringa doc[1-3] la shell prendera'
in considerazione unicamente i file doc1, doc2 e doc3. E' possibile combinare tutti questi caratteri speciali in qualsiasi
modo, percio' una stringa del tipo d?c[1-3].* e' perfettamente valida. Supponendo infatti di avere all'interno della nostra
directory i file doc1.txt, dic2.txt, dec3.doc, documenti, lettere, fax e moduli, con la stringa d?c[1-2].* prenderemmo in
considerazione unicamente i file doc1.txt, dic2.txt e dec3.doc.
Quando Unix, e di conseguenza anche Linux, quando vennero sviluppati, si volle mantenere indipendenti la struttura logica
dei file dalla conformazione del supporto fisico, di conseguenza venne sviluppato il concetto secondo il quale qualsiasi
dispositivo fisico puo' essere visto logicamente come un file, ossia come una sequenza continua di byte. Questo concetto
logico si estende anche alle operazioni di input ed output, infatti in queste operazioni i dati sono organizzati come
sequenze continue di byte. I dati introdotti in input con la tastiera vengono inseriti all'interno di un canale costituito
da una sequenza continua di byte. Allo stesso modo i dati prodotti a video vengoni inseriti all'interno di un altro canale.
Tali canali vengono definiti standard input e standard output. Pertanto la tastiera e' il canale standard
input ed il video e' il canale standard output. Qualsiasi comando quindi, accetta in input dei valori che legge dallo
standard input (la tastiera) e produce dei risultati scrivendoli nello standard output (il video). Ma un comando puo' produrre
anche dei messaggi di errore se per esempio vengono introdotti dei valori in input non validi. I messaggi di errore dei
comandi vengono scritti in un terzo canale, lo standard error. Lo standard error generalmente coincide con lo standard
output, nel senso che sia il risultato di un comando che eventuali errori vengono visualizzati a video.
Digitando il comando cat pippo, otterremo a video il contenuto del file pippo, in quanto cat accetta dallo standard input (la tastiera)
l'argomento pippo e lo invia allo standard output (il video). Cosa accade pero' se si digita cat senza argomenti e si preme
il tasto invio? Verra' eseguito il comando cat che leggera' lo standard input. In pratica ěl comando cat accetta da tastiera
degli argomenti. A questo modo e' possibile scrivere un documento come una lettera ad esempio. Per terminare la scrittura
della lettera occorre premere la combinazione di tasti CTRL-D. Tale combinazione di tasti corrisponde infatti al carattere
di fine file (EOF, cioe' End Of File). Infatti lo standard input e' un file come un altro. Usando CTRL-D scriviamo il carattere
di fine file ed il comando cat smettera' di leggere cio' che digitiamo.
Questi 3 canali sono dei file ben distinti e separati, e questo e' un concetto importante da tenere a mente, poiche' Linux (cosi' come Unix)
ci consente di redirigere un canale standard da o verso un file. E' possibile ad esempio inviare l'output prodotto da un comando
non a video (il canale standard output) ma all'interno di un file. Oppure e' possibile far si che un comando accetti in input
dei valori prendendoli da un file piuttosto che dalla tastiera. Queste operazioni di redirezione vengono effettuate utilizzando
gli operatori di redirezione '<', '>' e '>>'. Il primo e' l'operatore di redirezione dell'input standard, mentre gli ultimi
due sono gli operatori di redirezione dell'output standard. Supponiamo che digitando il comando ls il sistema produca a video
la seguente lista di file:
pippo
supponiamo ora di voler conservare questo elenco di file all'interno di un documento chiamato disney.txt. Bene, per eseguire
tale operazione dovremmo redirigere l'output standard (il video) all'interno del file disney.txt tramite l'operatore '>' in
questo modo:
ls > disney.txt
eseguendo tale comando la shell interpretera' l'operatore '>' redirigendo il risultato del comando ls all'interno del file
disney.txt. In altre parole tale comando fornisce le seguenti istruzioni per la shell: 'esegui il comando ls ma non inviare
il risultato a video perche' lo devi inviare all'interno del file disney.txt; se tale file non esiste crealo'. Cosi' la shell
creera' il file disney.txt ed inviera' l'output del comando ls all'interno di tale file. Qualora il file disney.txt fosse
gia' presente, la shell lo creera' nuovamente, distruggendo eventuali dati gia' presenti. Nel nostro esempio il comando
ls > disney.txt creera' il file disney.txt scrivendo all' interno i seguenti valori:
pippo
per visualizzare il contenuto del file disney.txt potremmo utilizzare il comando cat:
cat disney.txt
Come possiamo notare all'interno del file disney.txt e' presente anche il nome disney.txt. Infatti con l'operatore > la shell
prima crea il file disney.txt e successivamente esegue il comando ls (che elenchera' anche il file appena creato).
Supponiamo ora di cancellare i file pluto topolino e minnie dalla nostra directory e di creare un file chiamato paperino.
ls (elenca i file della directory)
Come abbiamo visto, eseguendo nuovamente il comando ls > disney.txt il contenuto precedente del file disney.txt viene azzerato
e vengono scritti all'interno solo i nomi pippo e paperino. Come fare per aggiornare il file disney.txt senza distruggere il
contenuto precedente? Potremmo usare l'operatore di redirezione dello standard output '>>'.
Infatti tale operatore non distrugge il file, in quanto permette di accodare alla fine del file il risultato prodotto
dal comando. Tornando al nostro esempio eseguendo il comando ls per la seconda volta ma utilizzando l'operatore >>
al posto dell'operatore > il contenuto del file non verrebbe cancellato in quanto il risultato del comando ls verrebbe
accodato ad esso. Percio' eseguendo il comando ls >> disney.txt si otterrebbe un file disney.txt contenente i nomi:
pippo, pluto, topolino, minnie, pippo e paperino.
Come si puo' osservare pippo e' ripetuto due volte in quanto il contenuto del file non e' stato cancellato. Ovviamente
per utilizzare il comando ls >> disney.txt occorre che il file disney.txt sia esistente, in caso contrario otterremmo un
errorre dalla shell. Infatti mentre l'operatore '>' crea un nuovo file, l'operatore '>>' accoda all'interno di un file gia'
esistente. L'operazione di redirezione puo' avvenire anche all'inverso, in quanto e' possibile redirigere il canale di
input standard. Generalmente i comandi accettano dei valori leggendoli dal canale di input standard cioe' dalla tastiera.
Per esempio il comando:
ls /home/mau/documenti
visualizza il contenuto della directory /home/mau/documenti. Tale directory e' un argomento che abbiamo fornito noi in input
digitandolo da tastiera. E' possibile pero' fare in modo che il comando ls prenda in input l'argomento '/home/mau/documenti'
non da tastiera ma ad esempio da un file. Cio' puo' essere fatto redirigendo l'input standard, cioe' copiando il contenuto
di un file all'interno del canale di input standard (ricordiamo che in Linux la struttura fisica dei dispositivi e' separata
dalla struttura logica dei file, pertanto un comando sa che deve accettare eventuali argomenti dal canale di input standard
ignorando completamente se tale canale sia la tastiera, il disco o qualsiasi altro supporto). Ad esempio il comando:
ls < pippo
redirige il contenuto del file pippo nell'input standard. Come gia' accennato, ogni volta che viene eseguito un comando la
shell si occupa di collegare input standard ed output standard al comando stesso: interpretando il comando, in questo caso
la shell collega l'output standard e l'input standard ma prima di far cio' redirige il contenuto del file pippo all'interno
dell'input standard. Percio' se all'interno del file e' presente la stringa '/home/mau/documenti', tale stringa verra' copiata
dalla shell (cioe' rediretta) nel canale di input standard. Quando il comando ls leggera' l'input standard, trovera' quindi
all'interno la stringa '/home/mau/documenti' appena copiata dalla shell. E' possibile redirigere l'input e l'output standard
contemporaneamente, infatti il comando:
cat < pippo > pluto
legge dal file pippo e scrive il risultato nel file pluto.
Spesso puo' essere utile inviare l'output di un comando non a video ma ad un altro comando prima di essere visualizzato.
Supponiamo ad esempio di voler visualizzare l'elenco dei file contenuti all'interno di una directory. Supponiamo anche
che il risultato prodotto sia un elenco interminabile di file. E possibile in questo caso utilizzare il comando more
che accetta in input dei dati e li visualizza a video sotto forma di pagine formattate, consentendo la visualizzazione di
una pagina per volta. Premendo un tasto qualsiasi il comando more visualizza la pagina successiva. Come e' possibile
collegare l'output prodotto dal comando ls al comando more? E' possibile utilizzando l'operatore di pipe '|'. E' il carattere
che si trova nel tasto posto sotto al tasto esc. Si ottiene premendolo contemporaneamente al tasto shift (il tasto che
permette di scrivere un carattere maiuscolo). Usando l'operatore di pipe '|' comunichiamo alla shell che e' necessario
collegare l'output standard del primo comando all'input standard del secondo comando. Ad esempio il comando:
ls | more
invia il risultato del comando ls al comando more. Il comando more a sua volta formatta tale risultato e lo invia a video.
E' possibile usare il comando less al posto del comando more, in quanto tale comando permette di scorrere le pagine avanti
ed indietro (less e' in sostanza una versione migliorata del comando more). Un'altra cosa che Linux permette di fare e'
consentire ad un comando di accettare degli argomenti sia dall'input standard e sia da un file. Redirigere l'input standard
con l'operatore < significa in pratica copiare dei dati da un file all'interno dell'input standard. Puo' essere utile pero'
far si che un comando accetti degli argomenti dall'input standard e contemporaneamente da un file. E' possibile farlo
utilizzando l'operatore '-'. L'operatore '-' rappresenta infatti l'input standard. Vediamo un esempio concreto. Supponiamo
di voler visualizzare il contenuto di un file a video usando il comando cat. Supponiamo anche di voler visualizzare prima
del contenuto del file anche il nome della directory corrente che lo contiene. Il nome della directory corrente si ottiene
con il comando pwd (Print Working Directory, cioe' stampa la directory di lavoro). Potremmo scrivere percio':
pwd | cat - miofile
cosa significano questi comandi? Il comando pwd crea in output il nome della directory, supponiamo /home/mau ma invece di
visualizzarlo a video lo invia tramite l'operatore di pipe '|' al comando cat. Cio' accade perche' la shell interpretando
la riga comandi, nota l'operatore di pipe '|' e quindi collega l'output standard del comando pwd all'input standard del comando
cat. Il comando cat quindi leggera' dall'input standard la riga prodotta da pwd (/home/mau) ma anche il nome del file miofile
(miofile e' stato digitato con la tastiera pertanto si trova all'interno dell'input standard). In altre parole il comando cat
visualizzera' prima il primo argomento letto dall'input standard, cioe' il nome della directory prodotto dal comando pwd e
successivamente il secondo argomento letto dall'input standard, cioe' il file miofile.
Il risultato finale sara' il nome della directory ed il contenuto del file prodotti a video. Cosi' come e' possibile forzare
un comando ad accettare un argomento dall'input standard ed un altro da un file e' anche possibile l'operazione inversa.
E' possibile cioe' inviare il risultato di un comando sia a video (output standard) che in un file. Cio' e' possibile
utilizzando il comando tee. Il comando cat pippo visualizza a video il contenuto del file pippo. Per visualizzarne il
contenuto e contemporaneamente scriverlo all'interno di un altro file, si puo usare il comando tee in questo modo:
cat pippo | tee pluto
il comando cat legge il contenuto del file pippo e lo invia allo standard output. La shell pero' notando l'operatore di pipe
'|' collega l'output standard del comando cat all'input standard del comando tee. Il comando tee a sua volta legge il contenuto
del file pippo dal suo input standard e lo invia sia a video che all'interno del file pluto. Vediamo a questo punto come redirigere
l'ultimo canale standard visto: il canale error standard. Quando un comando viene eseguito, normalmente viene prodotto un
risultato a video. Se pero' sbagliamo qualcosa nel digitare il comando, viene prodotto a video un messaggio di errore.
Supponiamo ad esempio di voler visualizzare il contenuto del file pippo ma digitando erroneamente scriviamo:
cat peppo
poiche' il file peppo non esiste, il comando cat visualizzera' a video il messaggio di errore cat: peppo not found. Infatti
normalmente il canale di standard error e' il video. Come fare per scrivere il messaggio di errore non a video ma all'interno
di un file? Ogni canale standard e' identificabile da un numero: 0 per il canale standard input, 1 per il canale standard
output e 2 per il canale standard error. Digitare il comando cat peppo > errori non produrrebbe il risultato voluto in quanto
l'operatore > redirige lo standard output all'interno del file errori ma non lo standard error. Poiche' il file peppo non esiste
il comando cat non scrive nulla nello standard output ma scrive un messaggio di errore nello standard error. Per specificare
quale canale redirigere nel file errori si puo' usare il numero che lo identifica. Nel nostro esempio desideriamo redirigere lo
standard error (2) e non lo standard output (1) all'interno del file errori. Pertanto possiamo scrivere:
cat peppo 2> errori
Il numero 2 a sinistra dell'operatore > specifica che il canale che intendiamo redirigere non e' lo standard output ma bensi'
lo standard error. Il comando cat pippo > pluto scrive il contenuto di pippo all'interno di pluto. Questo perche' per default
l'operatore > redirige lo standard output. In pratica e' la stessa cosa che scrivere cat pippo 1> pluto, in quanto in tal caso
1 se non specificato e' sottinteso. Diverso e' il comando 'cat pippo 1> dati 2> errori'. Qui si vuole infatti specificare
che occorre inviare il contenuto di pippo all'interno del file dati ed eventuali errori all'interno del file errori.
Tanto per complicare un po' di piu' le idee, illustriamo come sia possibile redirigere un canale standard all'interno
di un altro canale standard. Fino ad ora abbiamo infatti rediretto un canale standard verso un file o viceversa, un file
verso un canale standard. Per far riferimento ad un canale standard occorre usare l'operatore &. Infatto &0 fa riferimento
al canale standard input, &1 fa riferimento al canale standard output e &2 fa riferimento al canale standard error. Quindi
la stringa '2>&1' significa: redirezione del canale standard error (2) nel canale standard output (&1). Vediamo ad esempio
il comando:
cat non_esiste 1> dati 2>&1
tale comando visualizza il contenuto del file non_esiste inviandolo non a video ma all'interno del file dati ed inoltre
invia eventuali errori all'interno dello stesso file. In questo caso poiche' il file non_esiste come dice il nome non
esiste ;o) verra' prodotto un messaggio di errore. Analizziamo il comando: cat legge dallo standard input il nome del file
da visualizzare ma poiche' non lo trova produce un errore; inoltre il comando cat sa che il contenuto di tale file dovrebbe
essere inviato all'interno del file dati e non a video ('1>' infatti redirige lo standard output nel file dati); infine cat
sa che lo standard error deve essere rediretto nello standard output ('2>&1' infatti redirige lo standard error nello standard
output). Il risultato e' che il messaggio di errore andrebbe scritto nello standard error ma, poiche' tale canale e' stato rediretto,
viene scritto nello standard output. Poiche a sua volta lo standard output e' stato rediretto nel file dati, il messaggio
di errore verra' scritto nel file dati. Seguendo lo stesso percorso logico, la stringa '1>&2' redirige lo standard output
verso lo standard error. Riassumendo, '2>&1' invia lo standard error verso lo standard output e 1>&2 produce il risultato
contrario.
Una variabile e' una parte della memoria RAM identificata da un nome che puo' contenere dei valori. E' una scatola nera,
un contenitore all'interno del quale possiamo collocare una data, un nome, una cifra e cosi' via. Quando viene definita
una nuova variabile, il sistema associa al nome di tale variabile un indirizzo di memoria RAM a partire dal quale viene
memorizzato un valore stabilito dall'utente. Per definire e valorizzare una variabile e' sufficiente assegnare un valore
ad un nome, ad esempio, il comando:
PIPPO=253
definisce una variabile di nome PIPPO ed assegna a questa variabile il valore '253'. In altre parole il sistema alloca uno spazio di memoria
RAM a partire da un indirizzo scelto da lui (ad esempio 12234) una zona all'interno della quale memorizza il valore 253.
Cio' significa che la cella di memoria 12234 contiene 2, la cella contigua 12235 contiene 5 e la cella contigua 12236
contiene 3. Queste 3 celle contigue rappresentano una entita' di nome PIPPO. Oltre a contenere valori numerici, una variabile
puo' contenere anche stringhe, cioe' insiemi di caratteri. Ad esempio il comando PIPPO=scatola, crea una variabile di nome
PIPPO all'interno della quale viene memorizzato la stringa 'scatola'. Molte variabili contengono dei valori utili al sistema.
Ad esempio la variabile USERNAME contiene il nome dell'utente che si e' collegato al sistema mentre la variabile HOME contiene
il path della directory home dell'utente (ad esempio /home/mau). Una stringa puo' contenere anche il carattere spazio, ma
in questo caso occorre racchiuderla tra doppi apici. Ad esempio il comando MIAVAR="ciao a tutti" crea una variabile di nome
MIOVAR e ne memorizza all'interno la stringa "ciao a tutti". Il carattere '=' rappresenta l'operatore di assegnamento, cioe'
l'operatore che assegna il valore alla variabile. Tra il nome della variabile, l'operatore '=' ed il valore vero e proprio
non devono essere presenti spazi. Quindi il comando MIAVAR = 234 non e' corretto, perche' sono presenti degli spazi. Invece
il comando MIAVAR=234 e' un comando corretto. Una variabile ha vita solo all'interno della shell nella quale viene creata, pertanto
cambiando shell, il sistema non riconosce piu' tale variabile. Come sappiamo e' possibile creare delle subshell, cioe' delle
shell all'interno di altre shell. Bene, se definiamo la variabile PIPPO all'interno di una data shell e successivamente
apriamo una seconda shell, la variabile PIPPO rimarra' sconosciuta alla seconda shell. Possiamo verificarlo con questa
sequenza di comandi:
PIPPO=maurizio (definisco una variabile di nome PIPPO che contiene la stringa 'maurizio')
Affinche' una variabile sia visibile all'interno di qualsiasi shell, occorre 'esportarla' mediante il comando export.
Ad esempio:
PIPPO="ciao a tutti"
Per visualizzare le variabili definite si puo' usare il comando set, mentre per visualizzare le variabili di ambiente
occorre usare il comando env. Le variabili di ambiente sono tutte quelle variabili predefinite all'interno della
shell che troviamo normalmente all'interno di un sistema Linux. Per visualizzare l'elenco di tali variabili usiamo il comando
env:
env
Per visualizzare il contenuto di una variabile invece, occorre usare il comando echo insieme all'operatore '$'.
L'operatore $ serve per far riferimento al contenuto di una variabile. Ad esempio il comando:
echo $PIPPO
visualizza a video il contenuto della variabile PIPPO.
I programmi che sono in esecuzione sotto Linux vengono definiti processi. Quando si esegue un comando come ad esempio ls,
viene messo in esecuzione un processo. Ogni processo sotto Linux viene identificato da un numero univoco: il PID. PID sta
per Process IDentifier cioe' identificatore del processo. A dire il vero i comandi eseguiti dagli utenti vengono definiti
job. Si tratta sempre di processi, ma i processi utente vengono definiti job per distinguerli dai processi di sistema. Un comando, come qualsiasi processo puo' essere eseguito in background (lett. in sottofondo) nel senso che mentre il comando
e' in esecuzione l'utente puo' eseguire altre attivita'. E' conveniente eseguire un comando in background quando la sua
esecuzione richiede del tempo. Ad esempio la ricerca di un file all'interno di un grosso disco scorrendo tutte le directory
richiede un po' di tempo: e' possibile eseguire tale ricerca in background e nel frattempo eseguire altre attivita'.
Per eseguire un comando in background e' sufficiente apporre il carattere di e commerciale '&' alla fine del comando. Ad esempio
per stampare un file molto grande si puo' lanciare il comando lpr in questo modo:
lpr dati &
il carattere & permette di eseguire il comando lpr in background, permettendoci di eseguire altre attivita' evitando
di dover aspettare che il comando termini la sua esecuzione. La riga presente sotto a quella che contiene il comando
rappresenta il numero del job (1) ed il PID del processo (4). Cio' significa che il comando lpr appena lanciato e'
identificato dal sistema come processo numero 534 e job numero 1. E' possibile eseguire in background piu' di un comando
contemporaneamente. Per visualizzare i comandi in esecuzione in background (cioe' i job) si utilizza il comando jobs.
jobs
Il comando jobs visualizza i comandi in esecuzione in background e per ogni comando viene indicato il numero del job, lo stato
del comando (running o stopped) ed il comando stesso. Un comando in stato running e' un comando in esecuzione mentre un comando
in stato stopped e' un comando fermo. Il carattere indica il job corrente, cioe' quello attualmente in esecuzione, mentre
il carattere - indica il prossimo job che verra' eseguito. Non bisogna confondere un job stopped da uno non ancora in esecuzione:
il primo e' un job fermo in attesa di essere riattivato o ucciso, il secondo e' un job attivo ma non ancora in esecuzione.
Questa distinzione e' importante perche' l'utente puo' spospendere un job e riattivarlo in qualsiasi momento. E' possibile
eseguire piu' comandi in background digitandoli sulla stessa riga e terminandoli con il carattere &:
lpr dati & cat *.txt > testo &
Linux avverte della conclusione di job solo quando si termina il comando corrente (ad esempio una sessione di editing in vi).
Per essere avvertiti della conclusione di un job si puo' utilizzare il comando notify. Usando il comando notify,
non appena un job termina Linux interrompe il comando corrente (indipendentemente dall'operazione che si sta svolgendo)
avvertendo l'utente della conclusione del job. Il comando notify accetta come parametro il numero del job che desideriamo
tenere sotto controllo. Nell'esempio precedente, digitando il comando notify %1 Linux avvisera' l'utente - interrompendo
qualsiasi azione stia facendo - non appena il comando 'lpr dati' (il job numero 1) sara' terminato. E' possibile portare
un comando da modalita' background a modalita' foreground (la normale modalita' di esecuzione dei comandi) utilizzando
il comando fg. E' anche possibile l'operazione opposta, cioe' da foreground a background mediante il comando bg.
E' possibile annullare l'esecuzione di un comando mediante il comando kill (lett. uccidi, uccidere).
Nell'esempio precedente il comando kill %2 annullera' l'esecuzione del job numero 2 ossia del comando 'cat *.txt > testo'.
E' possibile annullare un comando indicando il numero del job od il numero del processo cioe' il PID.
E' possibile anche sospendere temporaneamente un comando senza ucciderlo definitivamente premendo la combinazione di tasti
CTRL-Z. L'utente puo' riattivare il comando un secondo tempo in modalita' background o foreground mediante i comandi
bg e fg. Tutto cio' puo' essere utile nei casi in cui l'esecuzione di un comando appena digitato richieda piu' tempo del
previsto. In questo caso e' possibile mettere in background il comando, ma occorre prima di tutto sospenderne l'esecuzione premendo i
tasti CTR-Z. Non e' possibile infatti mettere il comando in background direttamente senza averne prima sospeso l'esecuzione.
Una volta sospesa l'esecuzione del comando, lo si puo' mettere in backgroun usando il comando bg:
lpr divinacommedia.txt (stampo tutta la divina commedia ;o)
Nei sistemi Linux e' possibile programmare la shell, cioe' creare dei programmi per eseguire automaticamente delle operazioni che altrimenti si dovrebbero eseguire manualmente. Ad esempio e' possibile creare un programma per effettuare periodicamente il salvataggio dei dati su un supporto esterno (nastro, floppy, CD-Rom etc), oppure si potrebbe scrivere un programma che controlla lo spazio occupato sul disco e produce delle statistiche. Non ci sono limiti alle possibili applicazioni che possono essere gestite automaticamente da un programma: l'unico limite e' la fantasia del programmatore. Bene, tali programmi vengono definiti script della shell (per chi conosce il SO MSDOS: possono essere paragonati ai file .bat).
Per scrivere uno script della shell si puo' utilizzare un qualsiasi editor di testo come VI, EMACS, JED e via dicendo. Una volta scritto lo script, per eseguirlo occorre renderlo eseguibile impostando i permessi di esecuzione (utilizzando il comando chmod) oppure usare il comando sh od il comando '.'. Entrambi questi comandi eseguono lo script che viene loro passato come argomento. Ad esempio, supponendo di aver scritto uno script chiamato pippo, impostandone i permessi di esecuzione con il comando chmod, tale file diventera' simile ad un comune comando Linux: digitandolo e premendo INVIO verra' eseguito:
chmod u x pippo
Uno script della shell puo' contenere dei comuni comandi Linux, delle righe di commento ed una prima riga di commento un po' speciale. Quando un file di script viene eseguito la shell legge tale file riga per riga ed esegue tutte le istruzioni che incontra: si tratta percio' di un programma intrpretato. Tutte le righe che iniziano con il carattere cancelletto '#' vengono trattate come commento e sono percio' ignorate dalla shell. Le righe di commento sono particolarmente utili nella scrittura di script complessi per descrivere lo scopo del codice che si sta scrivendo. La primissima riga di commento pero' ha una funzione ben precisa: indicare il tipo di shell che potra' eseguire lo script ed eventualmente la locazione del disco o piu' esattamente il path per richiamare tale shell. Nel caso questa prima riga di commento venga omessa verra' chiamata la shell di default, cioe' la shell BASH. Infatti se il primo carattere e' uno spazio si suppone che tale script e' eseguibile dalla shell bash, se tale carattere e' un cancelletto si suppone che la shell da usare sia la TCSH. Inoltre e' possibile scrivere il carattere ! dopo il carattere # per specificare una shell diversa, ma in questo caso occorre anche indicare il path per reperire tale shell: #!/bin/sh. Quest'ultima notazione e' indispensabile se si utilizza una shell e si crea uno script per un'altra shell. Ad esempio se si utilizza la shell TCSH e si scrive uno script per la shell BASH e' indispensabile iniziare tale script con la stringa: #!/bin/sh, dove /bin/sh e' il path di default della shell BASH (ovviamente se in un particolare sistema la shell BASH si trova in una locazione diversa il relativo path da specificare dovra' essere diverso). Il comando echo visualizza in output una stringa. Vediamo un classico esempio di programma che utilizza il comando echo:
mioscript e' il nome dello script e contiene al suo interno le seguenti istruzioni:
Uno script generalmente accetta dei dati in input e genera dei dati in output: il comando read permette di leggere l'input ed il comando echo permette di scrivere in output. Ad esempio:
lo script mioscript contiene:
nello script appena visto l'istruzione read legge lo standard input e lo mette nella variabile $qualcosa, successivamente il comando echo visualizza il contenuto della variabile. Poiche' la stringa passata al comando echo e' inserita tra una coppia di doppi apici, eventuali caratteri speciali all'interno della variabile qualcosa non vengono valutati. Nel caso occorresse valutare eventuali caratteri speciali occorrera' eliminare i doppi apici. Ad esempio si potrebbe creare un comando che prendesse in considerazione anche eventuali caratteri speciali digitati dall'utente per effettuare alcune elaborazioni. Osserviamo il seguente script:
lo script elenco contiene:
l'utente digita il nome dello script (elenco) seguito dall'argomento *.txt. L'asterisco e' un carattere speciale che in questo caso viene preso in input dallo script e valutato in quanto la variabile $nomi non e' posta tra doppi apici. Percio' il comando ls accetta in input il contenuto della variabile passata allo script elenco e cioe' '*.txt'. Ad ogni modo uno script puo' leggere dei dati anche da se stesso:
lo script inviamail contiene:
la stringa <<fine significa: prendi in input tutto cio' che trovi da questo punto fino alla parola 'fine'. Se non si specifica un punto di terminazione occorrera' inserire il carattere di fine file CTRL-D. Ovviamente dopo i caratteri << e' possibile scrivere qualsiasi cosa come ad esempio <<stop, <<end e via dicendo.
Come qualsiasi comando Linux, anche gli script accettano degli argomenti in input. Per far riferimento ad un argomento e' possibile usare il simbolo $ seguito dal numero dell'argomento: $0 e' il nome dello script, $1 e' il primo argomento, $2 e' il secondo, $3 il terzo e cosi' via. $# rappresenta il numero degli argomenti passati in input e $* rappresenta tutti gli argomenti. Un esempio chiarira' il concetto:
mio script arg1 arg2 arg3
Veniamo ora alla prima istruzione utilizzabile all'interno di uno script: l'istruzione let. Let confronta due valori o permette di eseguire delle operazioni aritmetiche. Attenzione: let confronta due valori e non due espressioni. Esempi:
let 3*5
come si puo' vedere se gli argomenti del comando let contengono spazi, occorre quotarli usando i doppi apici. Il comando while appena visto e' una struttura di controllo che vedremo successivamente insieme alle altre strutture (if, for, for-in e case) in quanto occorre prima introdurre la struttura di controllo test. Il comando test permette di confrontare due valori. E' possibile confrontare due valori usando il comando test o inserendo l'espressione di confronto all'interno di una coppia di parentesi quadre. Per verificare l'uguaglianza tra due valori occorre usare il simbolo '=' oppure l'opzione -eq del comando test. Viceversa, per verificare la disuguaglianza tra due valori occore usare il simbolo "!=":
num=2
la verifica dei valori usando il comando test o le parentesi quadre e' usata all'interno di strutture di controllo come while, if, for, for-in e case- La sintassi della struttura di controllo if e' la seguente:
if comando-linux
Ogni comando linux quando termina restituisce un codice di errore che puo' essere 0 se il comando non ha successo o 1 se il comando e' andato a buon fine. Tale codice di errore viene verificato dalla struttura di confronto if: se e' 1 vengono eseguiti i comandi successivi alla parola then, in caso contrario vengono eseguiti i comandi successivi alla parola else. Vediamo il funzionamento della struttura di controllo if con lo script 'argomenti' che accetta degli argomenti in input e verifica che il numero di questi sia corretto: se viene passato piu' di un argomento visualizza un messaggio di errore:
if [$# -ne 1]
e' possibile 'nidificare' le if, ossia effettuare piu' controlli usando la sintassi 'elif' (elif sta per 'else if'). In altre parole se non si verifica la condizione testata vengono eseguiti i comandi successivi alla parola else ma a questo punto e' possibile eseguire un altro controllo utilizzando un altro comando if dopo la parola elif:
if [conddizione1]
come abbiamo visto il costrutto if permette di verificare l'esito di un comando Linux: e' possibile pero' verificare l'esito di due o piu' comandi Linux usando gli operandori logici && e ||. L'operatore logico && corrisponde all' and logico mentre l'operatore || corrisponde all' or logico. Cio' significa che se si vuole verificare che due o piu' comandi siano andati a buon fine contemporaneamente occorre usare l'operatore &&, mentre se si vuole verificare che almeno uno dei comandi sia andato a buon fine occorre usare l'operatore ||: comando1 && comando2 oppure comando1 || comando2. Nel primo caso viene eseguito tutto cio' che si trova dopo la parola then solo se entrambi i comandi hanno esito positivo mentre nel secondo caso e' sufficiente che almeno uno dei due comandi abbia esito positivo. Quando occorre verificare piu' condizioni, e' conveniente usare la struttura di controllo case. Vediamo il costrutto case con un esempio di script che visualizza un menu dove e' possibile scegliere tra le varie opzioni per visualizzare i file:
echo "scegli una opzione tra le seguenti:
cosi' come per il costrutto if anche il costrutto case deve terminare con una parola particolare: esac. Come si puo' osservare fi e' if letto in senso contrario ed esac e' case letto in senso contrario. ;o) Vediamo infine i costrutti while, for e for-in. Il costrutto while permette di eseguire un ciclo di comandi mentre e' verificata una condizione. Quando la condizione non e' piu' verificata il ciclo si interrompe e lo script prosegue dall' istruzione successiva al blocco del while. La sintassi dell'istruzione while e' la seguente:
while comando-linux
Il costrutto for permette di costruire cicli di comandi. Verranno eseguiti tanti cicli quanti sono gli argomenti passati allo script. Ogni argomento viene spostato all'interno di una variabile che verra' verificata dal ciclo di for. Vediamo un esempio con lo script 'copiafile' che permette di salvare i file specificati all'interno di una data directory:
for miofile
il costrutto for-in e' molto simile al costrutto for con la sola differenza che l'elenco dei valori non viene preso dall'elenco degli argomenti passati allo script ma dall'elenco fornito direttamente all'interno del costrutto for-in:
for variabile in pippo pluto topolino
Infine il comando exit permette di uscire immediatamente dallo script fornendo un codice di errore che puo' essere 0 o qualsiasi altro numero. Non appena viene incontrato il comando exit, lo script termina ed il controllo torna alla shell.
Una espressione regolare e' una stringa che contiene caratteri speciali. I caratteri speciali delle espressioni regolari pero' sono diversi dai caratteri speciali della shell: i primi consentono di effettuare ricerche all'interno di un testo mentre gli altri operano sui nomi di file. Le espressioni regolari possono essere utilizzate da molti filtri come ad esempio grep, sed e awk. I caratteri speciali sono l'accento circonflesso, il dollaro, l'asterisco, il punto e le parentesi quadre. Il segno ^ (accento circonflesso) ed il segno $ (dollaro) indicano rispettivamente l'inizio della riga e la fine della riga. Per ricercare tutte le righe all'interno di un testo che iniziano con la parola 'pippo' occorre definire una espressione regolare in questo modo: ^pippo. Al contrario per ricercare all'interno di un testo tutte le righe che terminano con al stringa 'pluto' occorre definire una espressione regolare in quest'altro modo: pluto$. Vediamo un esempio:
cat testo
il primo comando grep ricerca le righe che iniziano per 'che' mentre il secondo ricerca le righe che terminano con 'lari. Per ricercare le righe che contengono unicamente una determinata stringa si possono combinare i caratteri ^ e $ insieme in questo modo: ^stringa$, dove stringa e' la parola da ricercare. Se infine si vogliono ricercare tutte le righe vuote si puo' costruire una espressione regolare che contenga unicamente i caratteri ^ e $. Esempio:
cat testo
Le espressioni regolari possono essere usate anche combinando piu' comandi attraverso le pipe:
ls -l | grep '^d'
i comandi precedenti elencano i file contenuti all'interno della directory corrente e di questi file estraggono solo quelli che iniziano per 'd', cioe' tutti i file che sono directory. Infatti il comando ls -l elenca tutti i file in modalita' estesa (-l sta per long). Ogni riga prodotta in output dal comando ls -l contiene un trattino '-' per i file comuni e una 'd' per le directory: tale output viene passato tramite pipe al comando grep che ricerca solo le righe che iniziano per 'd'. Il risultato finale e' l'elenco delle directory contenute all'interno della directory corrente. Un altro carattere speciale e' il punto: tale simbolo significa qualsiasi carattere. Ad esempio la stringa 'a.a' individua tutte le stringhe che iniziano per a, terminano per a e contengono un qualsiasi altro carattere. Le stringhe che soddisfano questa espressione regolare possono essere: ala, ara, a a, ava, aka e via dicendo. E' possibile usare piu' punti, ad esempio l'espressione regolare: bar.. trova tutte le stringhe che iniziano per bar e contengono 2 altri caratteri qualsiasi. Le stringhe che soddisfano tale espressione possono essere: barca, barza, barone, baronetto e via dicendo. Il carattere '*' posto all'interno di una espressione regolare trova sequenze di 0 o piu' caratteri uguali al carattere che lo precede. Ad esempio bo* permette di trovare stringhe come boomerang, bossolo, boa e cosi' via. L'ultima serie di caratteri speciali usabili nelle espressioni regolari sono le parentesi quadre. Le parentesi quadre permettono di specificare un particolare carattere o una particolare sequenza di caratteri. Vediamo un esempio:
gruppo[145]
l'espressione regolare appena vista individua tutte le stringhe che iniziano per gruppo e terminano con 1, 4 o 5. Le stringhe gruppo1, gruppo2 e gruppo4 soddisfano i criteri ma la stringa gruppo9 o la stringa gruppo6 non soddisfano i criteri e pertanto non verranno individuate. La stringa gruppo2 soddisfa i criteri ma la stringa Gruppo2 non li soddisfa. Infatti 'gruppo2' e 'Gruppo2' sono due stringhe diverse. E' possibile pero' individuare entrambe le stringhe in questo modo:
[gG]gruppo[2]
E' possibile effettuare delle ricerche procedendo in senso inverso, cioe' individuando non tanto le stringhe da trovare ma bensi' le stringhe che non devono essere trovate. Per effettuare cio' e' possibile usare il simbolo '^' per escludere alcuni caratteri dalla ricerca. L'accento circonflesso si deve trovare tra la prima parentesi quadra ed il primo carattere all'interno delle parentesi quadre:
gruppo[^3456789]
l'espressione regolare esposta individua le stringhe gruppo1 e gruppo2 ma non le stringhe gruppo3, gruppo4 o gruppo9, in quanto terminano con un carattere che non deve essere presente: tutte le stringhe che terminano con 3,4,5,6,7,8 o 9 non verranno individuate. Se viene posto un trattino all'interno delle parentesi quadre viene definita una sequenza di caratteri. Ad esempio l'espressione regolare [A-Z] individua tutti i caratteri dell'alfabeto maiuscoli mentre [a-z] individua quelli minuscoli. Allo stesso modo l'espressione regolare [0-9] individua tutti i numeri da 0 a 9. Per includere anche il trattino nella ricerca, occorre usare il carattere '\' come carattere di quotazione: [0-9\-]. Tale espressione individua le stringhe che terminano con un numero o con un trattino. E' possibile combinare tutti questi caratteri speciali insieme per costruire delle stringhe di ricerca particolarmente efficaci. Ad esempio la stringa [0-9][0-9]* significa qualsiasi stringa che inizia con un numero e che termina con uno o piu' numeri: in sostanza vengono individuate solo stringhe numeriche. Allo stesso modo la stringa [A-Z][A-Z]* individua qualsiasi stringa composta da caratteri maiuscoli. Esempio:
I PC IBM sono stati i primi personal computer della storia e sono nati nel 1981
all'interno della riga esposta, l'espressione regolare [A-Z][A-Z]* individua le stringhe PC ed IBM mentre l'espressione regolare [0-9][0-9]* individua la stringa 1981. Le espressioni regolari possono essere particolarmente efficaci:
ls -l | grep '^......r.x'
i comandi esposti permettono di individuare tutti i file per i quali tutti gli altri utenti (proprietario e gruppo esclusi) posseggano i permessi di lettura ed esecuzione. Ecco un riepilogo dei caratteri speciali utilizzabili all'interno di espressioni regolari:
^ inizio riga
Infine esistono alcuni comandi che accettano anche altri caratteri come ad esempio il comando egrep. Il comando egrep infatti accetta anche i simboli: |, (), e ?. Il simbolo | rappresenta l' OR logico, cioe' permette di indicare delle stringhe alternative. Ad esempio 'frutta|verdura' individua sia la parola frutta che la parola verdura. Le parentesi permettono di concatenare piu' stringhe: (latte(intero|scremato). Il carattere ricerca una o piu' ripetizioni del carattere precedente, ad esempio o individua una o piu' o come ad esempio zoo, boomerang e via dicendo. Il carattere ? infine, individua 0 o 1 istanze del carattere precedente.
I filtri sono comandi che leggono dei dati, li elaborano ed inviano in output il risultato. I dati possono provenire
da file, dispositivi o possono essere l'output di altri comandi. L'output di un filtro e' generalmente l'output
standard (il video) ma puo' essere rediretto verso un file, un dispositivo od un altro comando che puo' essere a sua
volta un filtro. Un esempio di filtro e' il comando cat (da conCATenate). Il comando cat accetta in input dei dati
e li visualizza a video. Se non viene specificato l'input, il comando cat accetta i dati dall'input standard (la tastiera).
Percio' il comando cat > lettera si mette in attesa di dati dalla tastiera e al termine del flusso li scrive all'interno
del file lettera:
cat > lettera
Per terminare l'input da tastiera occorre premere la combinazione dei tasti CTRL e D che invia il carattere
di fine file. I filtri head (testa) e tail (coda) servono per visualizzare le prime righe di un testo (head) o
le ultime righe (tail). Ad esempio il comando head -2 visualizza le prime due righe di un testo:
cat lettera
mentre il comando tail -2 lettera visualizza le ultime due:
cat lettera
Altri esempi di filtri sono i comandi wc (Word Count) spell e sort. Il comando wc conta il numero di righe, parole e
caratteri (inclusi i caratteri di fine riga) presenti all'interno di un file. Il comando spell legge un file e produce
in output tutte le parole errate che trova (utilizzando il dizionario inglese). Il comando sort legge un file e lo riproduce
in output in modo ordinato. Un altro esempio di filtri sono i comandi grep ed fgrep. Tali comandi ricercano una stringa
all'interno di un file. Ad esempio, se all'interno di una directory con molti file esiste un file al cui interno e' presente
la stringa 'pippo' ma non ricordiamo piu' il nome di tale file, e' possibile individurarlo utilizzando il comando grep. Il comando grep accetta due argomenti, il primo e' la stringa da ricercare, il secondo e' un elenco di file. Per specificare
l'elenco di file e' anche possibile usare i caratteri speciali come '*'. Esempio:
cat lettera
se la stringa da ricercare contiene degli spazi occorre scriverla tra apici altrimenti il comando grep interpretera' lo spazio come un delimitatore considerando gli altri argomenti successivi al primo come nomi di file all'interno dei quali
effettuare la ricerca. Esempio:
cat lettera
qualora non fossero stati digitati gli apici il comando grep avrebbe ricercato la stringa 'caro' all'interno dei file: amico, lettera e documento. Occorre ricordarsi che Linux e' case sensitive, cioe' fa differenza tra caratteri maiuscoli e caratteri
minuscoli:
cat lettera
il comando grep in questo caso ricerca la stringa 'caro amico' all'interno dei file lettera e documento ma non produce alcun
risultato in quanto 'Caro amico' e 'caro amico' sono due stringhe diverse. Per effettuare una ricerca senza badare ai caratteri maiuscoli o minuscoli occorre usare l'opzione -i: grep -i 'caro amico' lettera documento. Il comando grep puo' anche funzionare al contrario, e' possibile cioe' ricercare tutte le righe che non contengono una data stringa. A tale
scopo occorre usare l'opzione -v. Il filtro fgrep e' piu' veloce di grep e puo' cercare contemporaneamente piu' stringhe nei file. Tale comando a differenza di grep non accetta pero' le espressioni regolari. Altri filtri utili sono i comandi diff e
sed. Il comando diff permette di confrontare due file per visualizzare le righe differenti. Il comando diff produce in output
le righe che risultano differenti, evidenziando quelle del primo file con il carattere '<' e quelle del secondo file con il carattere '>'. Il comando diff inoltre indica le operazioni che occorre effettuare per rendere i due file uguali. Sono possibili 3 operazioni: a, d o c. L'operazione a significa aggiungere, l'operazione d significa cancellare e l'operazione c
significa sostituire. Un esempio chiarira' il funzionamento di diff:
cat frutta
cioe': sostituire la terza riga del primo file con le righe dalla terza alla quinta del secondo file. La riga del primo file da sostiture e' < banane le righe del secondo file sono > carote, > pomodori e > cavoli. Per ignorare le differenze tra caratteri maiuscoli e caratteri minuscoli e' possibile usare l'opzione -i. Ovviamente e' possibile reindirizzare l'output del comando diff all'interno di un file: diff frutta fruttaeverdura > differenze. Esistono molti altri filtri come join, cut, paste, egrep, comm, cmp, tee, sort, pr, sed...tra questi un filtro molto usato e' il comando sed. Sed sta per Stream EDitor, cioe' editor di flusso: si tratta in sostanza di un editor di riga. Il comando sed accetta in input un comando di editing ed un elenco di file e genera in output una copia modificata di tali file. Esempio:
cat frutta
nell'esempio appena visto il comando sed cancella la terza riga dal file frutta. Il comando sed puo' effettuare varie operazioni di editing (inserimento, cancellazione, sostituzione etc.): per conoscere l'elenco completo delle operazioni di editing effettuabili consultare la relativa pagina di man (man sed).
Inizio della guida
Il filesystem
Indice
tipologie di comandi
Copyright (c) 2002-2003 Maurizio Silvestri |