[Blog] [MP3 Musica] [MP3 Audiobook] [Letture Creative] [Musica Creativa]
[Deutsch] [Español] [Português]
[Punch] [Appunti di informatica libera]
[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [violazione licenza] [translators] [docinfo] [indice analitico] [volume] [parte]
I sistemi operativi Unix non sono «facili»; tuttavia, può essere relativamente facile l'installazione della maggior parte delle distribuzioni GNU esistenti.
Questo capitolo raccoglie alcuni esercizi pratici che dovrebbero essere svolti da chi non ha esperienze con i sistemi operativi Unix e simili. Sono pensati per essere svolti su un elaboratore isolato, nel senso che non vengono trattate le funzionalità di rete.
Chi non ha la possibilità di disporre di un sistema Unix funzionante, farebbe bene ugualmente a leggere questo capitolo anche se non può fare subito delle prove pratiche. Gli esempi sono mostrati in modo da essere abbastanza vicini all'interazione che avviene effettivamente tra l'utente e il sistema operativo.(1)
Gli esercizi proposti assumono che si tratti di un sistema GNU/Linux configurato nel modo seguente:
disponibilità di diverse utenze (account) in modo da poter verificare l'effetto di comandi che intervengono sull'identità dell'utente (è importante che chi svolge gli esercizi possa accedere anche come utente root per potere eseguire la procedura di arresto del sistema, shutdown, in modo normale);
gli utenti dispongano di gruppi personali, per cui, l'utente tizio sia abbinato al gruppo tizio, l'utente caio sia abbinato al gruppo caio,...;
su;
console virtuali;
si possano gestire file system Ext2 (ext2), Ext3 (ext3), Dos-FAT (msdos) e Minix (minix);
la directory /mnt/ sia disponibile per l'innesto temporaneo di altri dischi (e non sia impegnata in condizioni normali).
Questi esercizi sono stati realizzati con un sistema GNU/Linux; pertanto alcune particolarità potrebbero non coincidere con altri sistemi Unix.
Per utilizzare il sistema occorre accedere attraverso un processo di identificazione. Per poter essere identificati e accettati occorre essere stati registrati in un'utenza, rappresentata in pratica da un nominativo-utente e da una parola d'ordine. È importante rammentare che l'uso di lettere maiuscole o minuscole non è equivalente. Nell'esempio proposto si suppone di accedere utilizzando il nominativo tizio, scritto così, con tutte le lettere minuscole, e la parola d'ordine tazza.
Si comincia dall'inserimento del nominativo, volontariamente errato.
login: tizia[Invio]
Anche se il nominativo indicato non esiste, viene richiesto ugualmente l'inserimento della parola d'ordine. Si tratta di una misura di sicurezza, per non dare informazioni sull'esistenza o meno di un nominativo-utente determinato.
Password: tazza[Invio]
Login incorrect |
Naturalmente, l'inserimento della parola tazza, in qualità di parola d'ordine, avviene alla cieca, nel senso che non appare come sembrerebbe dall'esempio. Ciò serve a evitare che un vicino indiscreto possa in seguito utilizzare tale informazione per scopi spiacevoli.
Se si sbaglia qualcosa nella fase di accesso (login), si deve ricominciare. Questa volta si suppone di eseguire l'operazione in modo corretto.
login: tizio[Invio]
Password: tazza[Invio]
Last login: Sun Nov 11 10:45:11 on tty1 |
Generalmente, dopo avere superato correttamente la procedura di accesso, si ottiene l'informazione sull'ultima volta che quell'utente ha fatto un accesso. Ciò permette di verificare in maniera molto semplice che nessuno abbia utilizzato il sistema accedendo con il proprio nominativo.
Successivamente si ottiene l'invito della shell (il prompt) che sta a indicare la sua disponibilità a ricevere dei comandi.
$ [Invio]
L'invito, rappresentato in questo esempio da un simbolo dollaro, può essere più o meno raffinato, con l'indicazione di informazioni ritenute importanti dall'utente. Infatti si tratta di qualcosa che ogni utente può configurare come vuole, ma ciò va oltre lo scopo di queste esercitazioni.
Spesso, per tradizione, l'invito termina con un simbolo che cambia in funzione del livello di importanza dell'utente: se si tratta di root si usa il simbolo #, altrimenti il dollaro, come in questo esempio.
Quando la stessa persona dispone di più di un'utenza, può essere opportuno, o necessario, agire sotto una diversa identità rispetto a quella con cui si accede attualmente. Questa è la situazione tipica in cui si trova l'amministratore di un sistema: per le operazioni diverse dall'amministrazione vera e propria dovrebbe accedere in qualità di utente comune, mentre negli altri casi deve utilizzare i privilegi riservati all'utente root.
Ci sono due modi fondamentali: concludere la sessione di lavoro e accedere con un altro nominativo-utente, oppure utilizzare il comando su cambiando temporaneamente i propri privilegi.
$ su caio[Invio]
Password: ciao[Invio]
Se la parola d'ordine è corretta si ottengono i privilegi e l'identità dell'utente indicato, altrimenti tutto resta come prima.
Un sistema GNU/Linux, installato in modo normale, consente l'utilizzo di diverse console virtuali (di solito sono sei) a cui si accede con la combinazione [Alt Fn] (dove n è un numero da uno a sei).
Quando è già stato fatto un accesso, si può iniziare un'altra sessione di lavoro in un'altra console.
[Alt F2]
In questo modo si passa alla seconda console virtuale e su questa si può eseguire un accesso differente. Le attività svolte nelle varie console virtuali sono indipendenti, come se avvenissero attraverso terminali fisicamente distinti.
Prima di proseguire con gli esercizi si deve ritornare alla console virtuale utilizzata in precedenza.
[Alt F1]
Quando la stessa persona può accedere utilizzando diversi nominativi-utente, potrebbe essere necessario controllare con quale identità sta operando. Negli esempi che seguono si suppone che sia riuscita l'esecuzione del comando su caio mostrato in precedenza.
$ whoami[Invio]
caio |
Il comando whoami («chi sono») permette di conoscere con quale identità si sta operando.
$ logname[Invio]
tizio |
Il comando logname permette di conoscere con quale identità ci si è presentati inizialmente, nel momento dell'accesso.
Per terminare una sessione di lavoro è sufficiente concludere l'attività della shell, ovvero di quel programma che mostra l'invito.
Se la situazione è quella degli esempi precedenti, si stava operando come utente caio dopo un comando su, mentre prima di questo si stava usando l'identità dell'utente tizio.
$ whoami[Invio]
caio |
$ exit[Invio]
In tal caso, il comando exit appena eseguito fa tornare semplicemente alla situazione precedente all'esecuzione di su
$ whoami[Invio]
tizio |
Il comando exit che chiude l'ultima shell, termina l'accesso al sistema.
$ exit[Invio]
login: |
Si ripresenta la richiesta di identificazione della procedura di accesso.
Lo spegnimento dell'elaboratore può avvenire solo dopo che il sistema è stato fermato, generalmente attraverso il comando shutdown che però è accessibile solo all'utente root.
login: root[Invio]
Password: ameba[Invio]
# shutdown -h now[Invio]
System is going down NOW!! ... |
Inizia la procedura di arresto del sistema, che si occupa di eliminare gradualmente tutti i servizi attivi. In un sistema GNU/Linux, alla fine viene visualizzato un messaggio simile a quello seguente:
Power down |
Quando questo appare è possibile spegnere o riavviare l'elaboratore.
Se si vuole utilizzare shutdown attraverso il comando su in modo da non dovere uscire e rifare un login, è possibile agire come di seguito.
$ su[Invio]
Quando si utilizza il comando su senza argomenti si indica implicitamente che si vuole ottenere l'identità dell'utente root.
Password: ameba[Invio]
# shutdown -h now[Invio]
Il comando su, appena mostrato, quando viene usato per acquisire i privilegi dell'utente root, mette a disposizione solo un ambiente limitato (si vuole fare riferimento alle variabili di ambiente e al loro contenuto). Per esempio, se l'utente caio diventa temporaneamente root, il contenuto della variabile di ambiente PATH cambia in modo strano:
$ whoami[Invio]
caio |
$ echo $PATH[Invio]
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/opt/prova/bin:/bin:./bin |
$ su[Invio]
Password: ameba[Invio]
# whoami[Invio]
root |
# echo $PATH[Invio]
/sbin:/bin:/usr/sbin:/usr/bin:/usr/bin/X11:/usr/local/sbin:/usr/local/bin |
Come si può notare, nel percorso che si ottiene in qualità di utente caio esistono anche le directory /usr/games/, /opt/prova/bin/ e ./bin/. Quando si diventa utenti root in questo modo, si ottengono percorsi aggiuntivi, ma ne spariscono altri, che in questo caso si presume siano accessibili in condizioni normali (con un accesso normale). Per risolvere il problema basta usare su con un'opzione speciale: -.
# exit[Invio]
$ su -[Invio]
Password: ameba[Invio]
# whoami[Invio]
root |
# echo $PATH[Invio]
/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:\ |
Il meccanismo attraverso cui si accede al sistema deve essere chiaro, prima di poter affrontare qualunque altra cosa. Per poter proseguire occorre essere certi che gli esempi visti fino a questo punto siano stati compresi, soprattutto, in seguito non viene più mostrato il modo con cui accedere, terminare una sessione di lavoro o cambiare identità.
È fondamentale tenere bene a mente che l'elaboratore non può essere spento prima di avere completato la procedura di arresto del sistema con shutdown.
In caso di dubbio è meglio ripetere l'esercitazione precedente.
La prima regola per una parola d'ordine sicura consiste nel suo aggiornamento frequente. Quando si cambia la parola d'ordine, viene richiesto inizialmente l'inserimento di quella precedente, quindi se ne può inserire una nuova, per due volte, in modo da prevenire eventuali errori di battitura. Di norma non vengono accettate le parole d'ordine troppo semplici (solo l'utente root dovrebbe avere la possibilità di assegnare parole d'ordine banali).
L'utente root può cambiare la parola d'ordine di un altro utente. Questa è la situazione comune di quando si crea una nuova utenza: è l'utente root che assegna la prima volta la parola d'ordine per quel nuovo utente.
# passwd tizio[Invio]
Trattandosi dell'utente root che cambia la parola d'ordine di un altro, viene richiesto semplicemente di inserire quella nuova (l'utente root non ha la necessità di conoscere la vecchia parola d'ordine di un altro utente).
New UNIX password: 123[Invio]
La parola d'ordine inserita (che nella realtà non si vede) è troppo breve e anche banale. Il programma potrebbe avvertire di questo, ma non dovrebbe opporsi:
BAD PASSWORD: it's a WAY too short |
Retype new UNIX password: 123[Invio]
passwd: all authentication tokens updated successfully |
La parola d'ordine è stata cambiata.
L'utente comune può cambiare la propria parola d'ordine, solo la propria, ma di norma non gli è consentito di assegnarsi una parola d'ordine troppo semplice. Nell'esempio, l'utente è tizio.
$ passwd[Invio]
Prima di accettare una nuova parola d'ordine, viene richiesta quella vecchia:
Changing password for tizio |
(current) UNIX password: 123[Invio]
Quindi viene richiesta quella nuova:
New UNIX password: albero[Invio]
BAD PASSWORD: it is based on a (reversed) dictionary word passwd: Authentication token manipulation error |
Come si vede in questo caso, la parola d'ordine albero viene considerata troppo semplice e il programma si rifiuta di procedere. Si decide allora di usare qualcosa di più complesso, o semplicemente più lungo.
$ passwd[Invio]
Changing password for tizio |
(current) UNIX password: 123[Invio]
New UNIX password: fra martino campanaro[Invio]
Si è optato per una parola d'ordine lunga. Occorre tenere a mente che conta la differenza tra maiuscole e minuscole e anche il numero esatto di spazi inseriti tra le parole.
Retype new UNIX password: fra martino campanaro[Invio]
passwd: all authentication tokens updated successfully |
Il cambiamento della parola d'ordine in un sistema Unix deve essere considerato una cosa abituale, anche per gli utenti comuni. Di norma, le parole d'ordine troppo semplici non sono accettabili.
I dati contenuti in un file system sono organizzati in modo gerarchico attraverso directory e sottodirectory. Prima di iniziare questa esercitazione è conveniente rivedere la sezione 8.7.
L'utente a cui ci si riferisce negli esempi è tizio.
Mentre si utilizza il sistema, i comandi che si eseguono risentono generalmente della posizione corrente in cui ci si trova, ovvero della directory attuale, o attiva. Tecnicamente non c'è bisogno di definire una directory corrente: tutte le posizioni nell'albero del file system potrebbero essere indicate in maniera precisa. In pratica, la presenza di questa directory corrente semplifica molte cose.
$ cd /usr/bin[Invio]
Eseguendo il comando precedente, la directory attuale dovrebbe divenire /usr/bin/. Per controllare che ciò sia avvenuto si utilizza il comando seguente:
$ pwd[Invio]
/usr/bin |
Il comando cd può essere utilizzato per cambiare la directory corrente, sia attraverso l'indicazione di un percorso assoluto, sia attraverso un percorso relativo. Il percorso assoluto parte dalla directory radice, mentre quello relativo parte dalla posizione corrente.
$ cd /usr/local[Invio]
Il comando soprastante cambia la directory corrente in modo che diventi esattamente /usr/local/. Il percorso indicato è assoluto perché inizia con una barra obliqua che rappresenta la directory radice.
$ pwd[Invio]
/usr/local |
Quando si utilizza l'indicazione di un percorso che non inizia con una barra obliqua, si fa riferimento a qualcosa che inizia dalla posizione corrente.
$ cd bin[Invio]
Con questo comando si cambia la directory corrente, passando in bin/ che discende da quella attuale.
$ pwd[Invio]
/usr/local/bin |
Ogni directory contiene due riferimenti convenzionali a due sottodirectory speciali. Si tratta del riferimento alla directory stessa che lo contiene, rappresentato da un punto singolo (.), assieme al riferimento alla directory genitrice, rappresentato da due punti in sequenza (..). Questi simboli (il punto singolo e quello doppio) sono nomi di directory a tutti gli effetti.
$ cd ..[Invio]
Cambia la directory corrente, facendola corrispondere alla genitrice di quella in cui ci si trovava prima; in altri termini si potrebbe definire questa directory come quella che precede la posizione di partenza. Si tratta di un percorso relativo che utilizza, come punto di inizio, la directory corrente del momento in cui si esegue il comando.
$ pwd[Invio]
/usr/local |
Gli spostamenti relativi che fanno uso di un movimento all'indietro possono essere più elaborati.
$ cd ../bin[Invio]
In questo caso si intende indietreggiare di una posizione e quindi entrare nella directory bin/.
$ pwd[Invio]
/usr/bin |
Lo spostamento a ritroso può essere anche cumulato a più livelli.
$ cd ../../var/tmp[Invio]
In questo caso si indietreggia due volte prima di riprendere un movimento in avanti.
$ pwd[Invio]
/var/tmp |
Gli spostamenti all'indietro si possono usare anche in modo più strano e apparentemente inutile.
$ cd /usr/bin/../local/bin/..[Invio]
Indubbiamente si tratta di un'indicazione poco sensata, ma serve a comprendere le possibilità date dall'uso del riferimento alla directory precedente.
$ pwd[Invio]
/usr/local |
La directory corrente può essere rappresentata da un punto singolo all'inizio di un percorso.(2) In pratica, tutti i percorsi relativi potrebbero iniziare con il prefisso ./ (punto, barra obliqua). Per quanto riguarda lo spostamento all'interno delle directory, ciò serve a poco, ma ritorna utile in altre situazioni.
$ cd ./bin[Invio]
A partire dalla directory corrente si sposta nella directory bin/.
$ pwd[Invio]
/usr/local/bin |
La directory corrente non corrisponde esattamente al concetto legato al riferimento .: il «file» . è un cortocircuito che ha ogni directory. Per esempio, il percorso uno/due/./tre è perfettamente equivalente a uno/due/tre. In pratica, quel punto che appare nel primo caso, rappresenta semplicemente uno spostamento nullo nella stessa directory uno/due. Lo si può verificare facilmente:
$ cd /usr/./local/./lib[Invio]
$ pwd[Invio]
/usr/local/lib |
Quando si indica un percorso relativo, è come inserire implicitamente all'inizio la directory corrente; pertanto, scrivere ./uno/due, significa indicare un concetto equivalente a directory_corrente/./uno/due. In questo senso, solo quando il punto si trova all'inizio di un percorso (che quindi risulta essere relativo), il punto rappresenta la directory corrente.
Ogni utente ha una directory personale, conosciuta come directory home, destinata a contenere tutto ciò che riguarda l'utente a cui appartiene. Usando il comando cd senza argomenti, si raggiunge la propria directory personale, senza bisogno di indicarla in modo esplicito.
$ cd[Invio]
$ pwd[Invio]
/home/tizio |
Alcune shell sostituiscono il carattere tilde (~), all'inizio di un percorso, con la directory personale dell'utente che lo utilizza.
$ cd ~[Invio]
$ pwd[Invio]
/home/tizio |
Nello stesso modo, un nominativo-utente preceduto da un carattere tilde, viene sostituito dalla directory personale dell'utente stesso.(3)
$ cd ~caio[Invio]
$ pwd[Invio]
/home/caio |
Prima di proseguire si ritorna nella propria directory personale.
$ cd[Invio]
La directory corrente è un punto di riferimento importante per i programmi e il cambiamento di questa posizione avviene attraverso il comando cd. Per conoscere quale sia la directory corrente si utilizza pwd. Si può fare riferimento alla directory genitrice di quella attuale con una sequenza di due punti (..), mentre quella attuale (nell'ambito del contesto in cui ci si trova) si può individuare con un punto singolo (.).
La navigazione all'interno delle directory, alla cieca, come visto negli esempi dell'esercitazione precedente, è una cosa possibile ma insolita: normalmente si accompagna con l'analisi dei contenuti di directory e file.
Le directory si esplorano con il comando ls
$ ls /bin[Invio]
arch dd gzip nisdomainname tar ash df hostname ping touch awk dmesg kill ps true basename dnsdomainname ln pwd umount bash doexec login rm uname bsh domainname ls rmdir vi cat echo mail rpm view chgrp egrep mkdir sed vim chmod ex mknod sh ypdomainname chown false more sleep zcat cp fgrep mount sort cpio gawk mt stty csh grep mv su date gunzip netstat sync |
Il comando ls /bin visualizza il contenuto della directory /bin/. I nomi che vengono elencati rappresentano file di qualunque tipo (sottodirectory incluse).
Una visualizzazione più espressiva del contenuto delle directory può essere ottenuta utilizzando l'opzione -l.
$ ls -l /bin[Invio]
-rwxr-xr-x 1 root root 2712 Jul 20 03:15 arch -rwxrwxrwx 1 root root 56380 Apr 16 1997 ash lrwxrwxrwx 1 root root 4 Oct 21 11:15 awk -> gawk -rwxr-xr-x 1 root root 18768 Apr 18 1997 basename -rwxrwxrwx 1 root root 412516 Jul 17 21:27 bash lrwxrwxrwx 1 root root 3 Oct 21 11:15 bsh -> ash -rwxr-xr-x 1 root root 22164 Mar 14 1997 cat -rwxr-xr-x 1 root root 23644 Feb 25 1997 chgrp -rwxr-xr-x 1 root root 23960 Feb 25 1997 chmod -rwxr-xr-x 1 root root 23252 Feb 25 1997 chown -rwxr-xr-x 1 root root 61600 Feb 25 1997 cp -rwxr-xr-x 1 root root 296728 Apr 23 1997 cpio ... |
In questo caso, è stato ottenuto un elenco più dettagliato che in particolare consente di distinguere il tipo di file, i permessi e l'appartenenza all'utente e al gruppo.
In precedenza è stato spiegato che ogni directory contiene due riferimenti convenzionali rappresentati da un punto singolo e da due punti in sequenza (. e ..). Negli esempi appena visti, questi non sono apparsi. Ciò accade perché i file il cui nome inizia con un punto non vengono presi in considerazione quando non si fa riferimento a loro in modo esplicito.
$ cd[Invio]
$ ls[Invio]
La directory personale di un utente potrebbe sembrare vuota, utilizzando il comando ls appena visto. Con l'opzione -a si visualizzano anche i file che iniziano con un punto (si osservi che in precedenza non sono apparsi i riferimenti alle voci . e ..).
$ ls -a[Invio]
. .bash_profile .riciclaggio .. .bashrc .screenrc .Xdefaults .fvwm2rc95 .twmrc .bash_history .mc.ext .xfm .bash_logout .mc.ini .xinitrc |
Anche il contenuto dei file può essere analizzato, entro certi limiti, soprattutto quando si tratta di file di testo. Per visualizzare il contenuto di file di testo si utilizzano generalmente i comandi cat e more.
$ cat /etc/fstab[Invio]
/dev/hda3 / ext3 defaults 1 1 /dev/hda2 none swap sw proc /proc ignore /dev/hda1 dos vfat quiet,umask=000 /dev/hdc /mnt/cdrom iso9660 ro,user,noauto /dev/fd0 /mnt/floppy vfat user,noauto,quiet |
Con il comando appena indicato è stata ottenuta la visualizzazione del contenuto del file /etc/fstab, che ovviamente cambia a seconda della configurazione del proprio sistema.
cat, usato così, non si presta alla visualizzazione di file di grandi dimensioni. Per questo si preferisce usare more, oppure il più raffinato less.
$ more /etc/services[Invio]
# /etc/services: # $Id: services,v 1.4 1997/05/20 19:41:21 tobias Exp $ # # Network services, Internet style # # Note that it is presently the policy of IANA to assign a single well-known # port number for both TCP and UDP; hence, most entries here have two entries # even if the protocol doesn't support UDP operations. # Updated from RFC 1700, ``Assigned Numbers'' (October 1994). Not all ports # are included, only the more common ones. tcpmux 1/tcp # TCP port service multiplexer echo 7/tcp echo 7/udp discard 9/tcp sink null discard 9/udp sink null systat 11/tcp users daytime 13/tcp daytime 13/udp netstat 15/tcp qotd 17/tcp quote msp 18/tcp # message send protocol msp 18/udp # message send protocol --More--(5%) |
[barra spaziatrice]
chargen 19/tcp ttytst source chargen 19/udp ttytst source ftp-data 20/tcp ftp 21/tcp fsp 21/udp fspd ssh 22/tcp # SSH Remote Login Protocol ssh 22/udp # SSH Remote Login Protocol telnet 23/tcp # 24 - private smtp 25/tcp mail # 26 - unassigned time 37/tcp timserver time 37/udp timserver rlp 39/udp resource # resource location nameserver 42/tcp name # IEN 116 whois 43/tcp nicname re-mail-ck 50/tcp # Remote Mail Checking Protocol re-mail-ck 50/udp # Remote Mail Checking Protocol domain 53/tcp nameserver # name-domain server domain 53/udp nameserver mtp 57/tcp # deprecated bootps 67/tcp # BOOTP server bootps 67/udp --More--(9%) |
Come mostrato, per passare alla schermata successiva, basta premere la [barra spaziatrice]. Per terminare, anche se non è stato visualizzato tutto il file, basta usare la lettera «q».
[q]
less funziona in modo analogo, con la differenza che si può scorrere il file anche all'indietro, usando intuitivamente la tastiera.
Il contenuto dei file può essere determinato attraverso il comando file, senza doverne visualizzare il contenuto. Ciò è molto importante, specialmente nelle situazioni in cui visualizzare un file è inopportuno (si pensi a cosa accadrebbe tentando di visualizzare un file eseguibile binario).
Il comando file si basa su una serie di stringhe di riconoscimento chiamate magic number (una sorta di «impronta»), definite in base alla tradizione dei sistemi Unix.
$ file /etc/*[Invio]
/etc/DIR_COLORS: English text /etc/HOSTNAME: ASCII text /etc/X11: directory /etc/adjtime: ASCII text /etc/aliases: English text /etc/aliases.db: Berkeley DB Hash file (Version 2, Little Endian,... /etc/at.deny: ASCII text /etc/bashrc: ASCII text /etc/cron.daily: directory /etc/cron.hourly: directory /etc/cron.monthly: directory /etc/cron.weekly: directory /etc/crontab: ASCII text /etc/csh.cshrc: ASCII text /etc/dosemu.conf: English text /etc/dosemu.users: ASCII text ... |
Il comando indicato come esempio visualizza l'elenco dei file contenuti nella directory /etc/, dove a fianco di ogni file appare la definizione del tipo a cui questo appartiene.
Questo metodo di riconoscimento dei dati non è infallibile, ma è comunque di grande aiuto.
Per controllare lo spazio disponibile nel disco (o nei dischi) si utilizza il comando df.
$ df[Invio]
Il risultato del comando potrebbe essere qualcosa di simile a quanto segue.
Filesystem 1024-blocks Used Available Capacity Mounted on /dev/hda4 648331 521981 92860 85% / /dev/hda1 41024 38712 2312 94% /dos |
Per controllare lo spazio utilizzato in una directory si può usare il comando du.
$ du /bin[Invio]
3168 /bin |
In questo caso, si determina che la directory /bin/ contiene file per un totale di 3 168 Kibyte.
L'analisi del contenuto di directory e file è un'operazione elementare, ma essenziale per la determinazione delle azioni da compiere in funzione di quanto si rivela in questo modo.
La creazione, la copia e l'eliminazione dei file sono operazioni elementari, ma importanti e delicate. Questa esercitazione deve essere fatta con cura e attenzione.
Esistono vari modi per creare un file. Il modo più semplice per creare un file vuoto è quello di usare il comando touch. Prima di tutto ci si sposta nella propria directory personale, che è il luogo più adatto per questo genere di esercizi.
$ cd[Invio]
$ touch pippo[Invio]
Dopo aver usato il comando touch per creare il file pippo non si ottiene alcuna conferma dell'avvenuta esecuzione dell'operazione. Questo atteggiamento è tipico dei sistemi Unix i cui comandi tendono a non manifestare il successo delle operazioni eseguite. Si può comunque verificare.
$ ls -l pippo[Invio]
-rw-rw-r-- 1 tizio tizio 0 Dec 23 10:49 pippo |
Il file è stato creato.
In questa fase degli esercizi, in cui non è ancora stato descritto l'uso di un programma per creare o modificare file di testo, è possibile vedere un metodo semplice per creare un file del genere. Si utilizza il comando cat in un modo un po' strano che viene chiarito più avanti.
$ cat > pippo2[Invio]
Da questo momento inizia l'inserimento del testo come nell'esempio mostrato qui di seguito.
Esiste anche un modo semplice di scrivere[Invio]
un file di testo.[Invio]
Purtroppo si tratta di una scrittura a senso unico.[Invio]
[Ctrl d]
L'inserimento del testo termina con la combinazione [Ctrl d].
Si può verificare che il file sia stato creato e contenga il testo digitato.
$ cat pippo2[Invio]
Esiste anche un modo semplice di scrivere un file di testo. Purtroppo si tratta di una scrittura a senso unico. |
La copia dei file può essere fatta attraverso l'uso del comando cp.
$ cp pippo2 pippo3[Invio]
Eseguendo il comando appena mostrato, si ottiene la copia del file pippo2 per generare il file pippo3. Come al solito, se tutto va bene non si ottiene alcuna segnalazione.
La copia di un gruppo di file può avvenire solo quando la destinazione (l'ultimo nome indicato nella riga di comando) è una directory già esistente.
$ cp pippo pippo2 pippo3 /tmp[Invio]
Con il comando precedente si copiano i file creati fino a questo punto nella directory /tmp/. La stessa cosa si può fare in modo più semplice utilizzando i caratteri jolly.
$ cp pippo* /tmp[Invio]
L'eliminazione dei file avviene normalmente per mezzo di rm. L'uso di questo comando deve essere fatto con molta attenzione, specialmente quando si agisce con i privilegi dell'utente root. Infatti, la cancellazione avviene senza obiezioni e senza richiedere conferme. Può bastare un errore banale per cancellare tutto ciò a cui si può accedere.
$ rm pippo pippo2[Invio]
Il comando appena mostrato elimina definitivamente e senza possibilità di recupero i file indicati: pippo e pippo2.
La cancellazione dei file può avvenire anche indicandone un gruppo attraverso l'uso dei caratteri jolly. L'uso di questi simboli rappresenta un rischio in più. Generalmente, quando non si ha ancora una buona preparazione e si può essere incerti sull'effetto di un comando di eliminazione, conviene prima controllare il risultato, per esempio attraverso ls.(4)
Volendo cancellare tutti i file il cui nome inizia per pippo, si potrebbe utilizzare il modello pippo*. Per sicurezza si verifica con ls.
$ ls pippo*[Invio]
pippo3 |
Risulta corrispondere al modello solo il file pippo3. Infatti, poco prima sono stati cancellati pippo e pippo2. In ogni caso, si vede che il modello è corretto e si procede con la cancellazione (tuttavia si deve fare attenzione ugualmente).
$ rm pippo*[Invio]
L'uso distratto di questo comando di eliminazione, può produrre danni gravi. Si pensi a cosa può accadere se, invece di digitare rm pippo* si inserisse accidentalmente uno spazio tra la parola pippo e l'asterisco. Il comando sarebbe rm pippo * e produrrebbe l'eliminazione del file pippo (se esiste) e successivamente l'eliminazione di tutti i file contenuti nella directory corrente (questo è ciò che rappresenta l'asterisco da solo). Come è già stato spiegato, rm non fa domande, così come accade con gli altri comandi, nel rispetto delle tradizioni Unix: quello che è cancellato è cancellato.
La creazione di file, normalmente vuoti, la copia e l'eliminazione, sono operazioni elementari ma fondamentali. Nella loro semplicità si tratta comunque di funzionalità che richiedono un po' di attenzione, soprattutto quando si interviene con i privilegi dell'utente root: con la copia si potrebbero sovrascrivere file già esistenti, con la cancellazione si potrebbe intervenire in un ambito diverso da quello previsto o desiderato.
Le directory possono essere viste come contenitori di file e di altre directory. La copia e l'eliminazione di directory ha delle implicazioni differenti rispetto alle stesse operazioni con i file normali. Continua a valere la raccomandazione di svolgere l'esercitazione con cura.
La creazione di una directory è concettualmente simile alla creazione di un file vuoto. Quando la directory viene creata è sempre vuota: si riempie utilizzandola. Una directory viene creata con il comando mkdir.
Prima di procedere ci si sposta nella propria directory personale e quindi si crea la directory mia/ discendente dalla posizione corrente.
$ cd[Invio]
$ mkdir mia[Invio]
Si può verificare con il comando ls.
$ ls -l[Invio]
... drwxr-xr-x 8 tizio tizio 1024 Dec 23 12:11 mia ... |
La lettera d all'inizio della stringa che identifica i permessi indica chiaramente che si tratta di una directory.
La copia delle directory avviene attraverso il comando cp con le opzioni -r oppure -R, tra le quali c'è una differenza sottile che però qui non viene approfondita.
$ cp -r mia mia2[Invio]
Con il comando appena visto, si ottiene la copia della directory mia/ in mia2/. La copia è ricorsiva, nel senso che comprende tutti i file contenuti nella directory di origine, assieme a tutte le eventuali sottodirectory, compreso il loro contenuto.
Normalmente, le directory si possono cancellare quando sono vuote, per mezzo del comando rmdir.
Valgono le stesse raccomandazioni di prudenza fatte in precedenza in occasione degli esercizi sulla cancellazione di file.
$ rmdir mia2[Invio]
Il comando appena mostrato elimina la directory mia2/.
L'eliminazione delle directory fatta in questo modo, cioè attraverso il comando rmdir, non è molto preoccupante, perché con esso è consentito eliminare solo directory vuote: se ci si accorge di avere eliminato una directory di troppo, si riesce facilmente a ricrearla con il comando mkdir.
Tuttavia, spesso si eliminano interi rami di directory, quando con un comando si vuole eliminare una o più directory e con esse il loro contenuto di file ed eventuali altre directory. Si dice in questo caso che si esegue una cancellazione ricorsiva.
Prima di proseguire, si prova a creare una struttura articolata di directory.
$ mkdir carbonio[Invio]
$ mkdir carbonio/idrogeno[Invio]
$ mkdir carbonio/ossigeno[Invio]
$ mkdir carbonio/idrogeno/elio[Invio]
Si dovrebbe ottenere una struttura organizzata nel modo seguente:
$ tree carbonio[Invio]
carbonio |-- idrogeno | `-- elio `-- ossigeno 3 directories, 0 files |
Se si tenta di eliminare tutta la struttura che parte da carbonio/ con il comando rmdir, si ottiene solo una segnalazione di errore.
$ rmdir carbonio[Invio]
rmdir: carbonio: Directory not empty |
Per questo bisogna utilizzare il comando rm con l'opzione -r. Tuttavia, il comando rm applicato in questo modo ricorsivo è particolarmente pericoloso se utilizzato in modo distratto.
$ rm -r carbonio[Invio]
La directory carbonio/ e tutto ciò che da essa discendeva non c'è più.
Si provi a pensare cosa può accadere quando si utilizzano i caratteri jolly: si cancellano indifferentemente file e directory che corrispondono al modello. C'è però ancora qualcosa di peggiore: l'insidia dei nomi che iniziano con un punto.
La cancellazione di directory il cui nome inizia con un punto è un'operazione estremamente delicata che merita una discussione a parte. Generalmente, quando si utilizzano i caratteri jolly per identificare un gruppo di nomi di file e directory, questi simboli non corrispondono mai ai nomi che iniziano con un punto. Questa convenzione è stata definita per evitare che con i caratteri jolly si possa intervenire involontariamente con i riferimenti standard delle directory: . (la directory stessa che lo contiene) e .. (la directory genitrice).
A questo fatto si è aggiunta la convenzione di nominare in questo modo (con un punto iniziale) file e directory che rappresentano la configurazione particolare di ogni utente. In tal modo, è come se tali file e directory fossero nascosti, per cui l'utente non risulta infastidito da questi che così non possono nemmeno essere cancellati involontariamente.
Potrebbe sorgere il desiderio di eliminare tutti questi file e tutte queste directory, utilizzando il modello .* (punto, asterisco), ma in questo modo si eliminerebbero anche i riferimenti standard: . e .., eliminando così anche la directory corrente, ma soprattutto quella genitrice (con tutto il suo contenuto).
Se il comando viene dato da un utente comune, questo riesce a eliminare solo i dati a cui può accedere, mentre se lo sbaglio viene fatto dall'utente root, tutto ciò che è stato selezionato erroneamente viene perduto.
Per concludere, il comando incriminato è rm -r .*. Chi ha letto si consideri avvisato!
Quando si copiano e si eliminano le directory sorge spontaneo il desiderio di intervenire in modo ricorsivo su tutto il contenuto della directory di partenza. I problemi maggiori cui si va incontro sono legati alla cancellazione ricorsiva, specialmente quando si pretende di eliminare i file e le directory il cui nome inizia con un punto, in modo globale, attraverso un modello fatto di caratteri jolly.
Negli ambienti Unix, lo spostamento e il cambiamento del nome di file e directory sono la stessa cosa. Un'altra particolarità dei sistemi operativi Unix è la possibilità di gestire i collegamenti a file e directory.
Lo spostamento di file e directory avviene per mezzo di mv. Per esercitarsi con questo comando si preparano alcuni file e alcune directory.
$ touch alfa[Invio]
$ touch beta[Invio]
$ mkdir gamma[Invio]
Come sempre è bene controllare.
$ ls -l[Invio]
... -rw-rw-r-- 1 tizio tizio 0 Dec 25 12:46 alfa -rw-rw-r-- 1 tizio tizio 0 Dec 25 12:46 beta drwxrwxr-x 2 tizio tizio 1024 Dec 25 12:46 gamma ... |
Si procede rinominando il file alfa in modo che diventi omega.
$ mv alfa omega[Invio]
$ ls -l[Invio]
... -rw-rw-r-- 1 tizio tizio 0 Dec 25 12:46 omega ... |
Volendo spostare una serie di file e directory in gruppo, è necessario che la destinazione sia una directory. Con il comando seguente si spostano i due file creati poco prima nella directory gamma/.
$ mv omega beta gamma[Invio]
$ ls -l gamma[Invio]
-rw-rw-r-- 1 tizio tizio 0 Dec 25 12:46 beta -rw-rw-r-- 1 tizio tizio 0 Dec 25 12:46 omega |
Generalmente, lo spostamento (o il cambiamento di nome) non fa differenza tra file normali e directory.
$ mv gamma /tmp[Invio]
Il comando precedente sposta la directory gamma/ in /tmp/.
È importante tenere presente che il comando mv non può cambiare una serie di nomi in modo sistematico. Per esempio, non si può cambiare *.mio in *.tuo.
La creazione di un collegamento è un'operazione simile alla copia, con la differenza che invece di creare un duplicato di file e directory, si genera un riferimento agli originali. Ne esistono due tipi: collegamenti simbolici e collegamenti fisici (questi ultimi conosciuti di solito come hard link). In questa esercitazione vengono mostrati solo collegamenti simbolici.
$ pwd[Invio]
/home/tizio |
Il comando utilizzato per creare questi collegamenti è ln; dal momento che si intendono mostrare solo quelli simbolici, viene usata sempre l'opzione -s.
Per esercitarsi con questo comando si preparano alcuni file e directory.
$ touch uno[Invio]
$ touch due[Invio]
$ mkdir tre[Invio]
Come sempre è bene controllare.
$ ls -l[Invio]
... -rw-rw-r-- 1 tizio tizio 0 Dec 25 12:46 due drwxrwxr-x 2 tizio tizio 1024 Dec 25 12:46 tre -rw-rw-r-- 1 tizio tizio 0 Dec 25 12:46 uno |
Come si accennava all'inizio, la creazione di un collegamento è un'operazione simile alla copia.
$ ln -s uno uno.bis[Invio]
Con il comando mostrato sopra, si ottiene un collegamento simbolico, denominato uno.bis, al file uno.
$ ls -l[Invio]
... lrwxrwxrwx 1 tizio tizio 3 Dec 25 12:47 uno.bis -> uno |
Da questo momento si può fare riferimento al file uno utilizzando il nome uno.bis.
La creazione di un collegamento a una directory può avvenire nello stesso modo visto per i file (a patto che si tratti di collegamenti simbolici).
$ ln -s /tmp miatemp[Invio]
Se il comando appena visto ha successo si può raggiungere la directory /tmp/ anche attraverso il riferimento miatemp.
La creazione di un gruppo di collegamenti con un solo comando, può avvenire solo quando la destinazione (l'ultimo nome sulla riga di comando) è una directory. In questo modo si ottiene la creazione di una serie di collegamenti al suo interno.
$ ln -s /home/tizio/uno* /home/tizio/due tre[Invio]
In questo caso, si generano una serie di collegamenti per tutti i file i cui nomi iniziano per uno e anche per il file due nella directory tre/.
$ ls -l tre[Invio]
lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:21 due -> /home/tizio/due lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:21 uno -> /home/tizio/uno lrwxrwxrwx 1 tizio tizio 19 Dec 25 15:21 uno.bis -> /home/tizio/uno.bis |
Si può osservare che è stato creato anche un collegamento che punta a un altro collegamento.
Se si cancellano questi collegamenti simbolici nella directory tre/, si può provare a vedere cosa può accadere se non si indica un percorso assoluto:
$ rm tre/*[Invio]
Intuitivamente si può ritenere che possa essere corretta la creazione dei collegamenti simbolici in questo modo:
$ ln -s uno* due tre[Invio]
Se però si va a controllare il contenuto della directory tre/, si può notare una cosa strana: i collegamenti simbolici puntano a loro stessi.
$ ls -l tre[Invio]
lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:25 due -> due lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:25 uno -> uno lrwxrwxrwx 1 tizio tizio 19 Dec 25 15:25 uno.bis -> uno.bis |
Inizialmente è difficile capire questa cosa. Conviene provare in modo ancora diverso:
$ rm tre/*[Invio]
$ ln -s ./uno* ./due tre[Invio]
$ ls -l tre[Invio]
lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:30 due -> ./due lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:30 uno -> ./uno lrwxrwxrwx 1 tizio tizio 19 Dec 25 15:30 uno.bis -> ./uno.bis |
Se non è ancora chiaro, si provi questo:
$ rm tre/*[Invio]
$ ln -s nero/marrone rosso/arancio giallo/verde tre[Invio]
$ ls -l tre[Invio]
lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:35 marrone -> nero/marrone lrwxrwxrwx 1 tizio tizio 15 Dec 25 15:35 arancio -> rosso/arancio lrwxrwxrwx 1 tizio tizio 19 Dec 25 15:35 giallo -> giallo/verde |
Si intende che i file nero/marrone, rosso/arancio e giallo/verde non esistono; tuttavia, i collegamenti simbolici vengono creati ugualmente.
Lo spostamento di file e directory avviene in modo simile alla copia, solo che l'origine viene rimossa. Lo spostamento di directory attraverso unità di memorizzazione differenti non è possibile. Lo spostamento erroneo può essere dannoso: se non si fa attenzione si può sovrascrivere qualcosa che ha già lo stesso nome dei file o delle directory di destinazione. Questo è lo stesso tipo di problema che si rischia di incontrare con la copia.
I collegamenti a file e directory permettono di definire percorsi alternativi agli stessi. I collegamenti simbolici vengono creati analizzando i nomi senza verificare che appartengano effettivamente a file o directory reali.
La shell è il mezzo attraverso cui si interagisce con il sistema. Il modo di inserire i comandi può cambiare molto da una shell all'altra. Gli esercizi proposti in questa sezione sono stati realizzati in particolare con la shell Bash, ma gran parte di questi possono essere validi anche per altre shell.
Il completamento automatico è un modo attraverso cui la shell Bash aiuta l'utente a completare un comando. La richiesta di completamento viene fatta attraverso l'uso del tasto [Tab]. Si preparano alcuni file di esempio. I nomi utilizzati sono volutamente lunghi.
$ touch microinterruttore[Invio]
$ touch microscopico[Invio]
$ touch supersonico[Invio]
Supponendo di voler utilizzare questi nomi all'interno di una riga di comando, si può essere un po' infastiditi dalla loro lunghezza. Utilizzando il completamento automatico si risolve il problema.
$ ls sup[Tab]
Dopo avere scritto solo sup, premendo il tasto [Tab] si ottiene il completamento del nome, dal momento che non esistono altri file o directory (nella posizione corrente) che inizino nello stesso modo. L'esempio seguente mostra lo stesso comando completato e terminato.
$ ls sup[Tab]ersonico[Invio]
Il completamento automatico dei nomi potrebbe essere impossibile. Infatti, potrebbe non esistere alcun nome che coincida con la parte iniziale già inserita, oppure potrebbero esistere più nomi composti con lo stesso prefisso. In questo ultimo caso, il completamento si ferma al punto in cui i nomi iniziano a distinguersi.
$ ls mic[Tab]ro
In questo caso, il completamento si spinge fino a micro che è la parte comune dei nomi microinterruttore e microscopico. Per poter proseguire occorre aggiungere un'indicazione che permetta di distinguere tra i due nomi. Volendo selezionare il primo di questi nomi, basta aggiungere la lettera i e premere nuovamente il tasto [Tab]. L'esempio seguente rappresenta il procedimento completo.
$ ls mic[Tab]roi[Tab]nterruttore[Invio]
L'utilizzo di caratteri jolly rappresenta una forma alternativa di completamento dei nomi. Infatti è compito della shell la trasformazione dei simboli utilizzati per questo scopo.
Per questo esercizio si utilizzano i file creati nella sezione precedente: microinterruttore, microscopico e supersonico. In seguito se ne vengono aggiunti altri quando l'esercizio lo richiede.
L'asterisco rappresenta una sequenza indefinita di zero o più caratteri di qualunque tipo, esclusa la barra obliqua di separazione tra le directory. Per cui, l'asterisco utilizzato da solo rappresenta tutti i nomi di file disponibili nella directory corrente.
$ ls[Invio]
Il comando ls appena mostrato serve a elencare tutti i nomi di file e directory contenuti nella directory corrente.
$ ls *[Invio]
Questo comando è un po' diverso, nel senso che la shell provvede a sostituire l'asterisco con tutto l'elenco di nomi di file e directory contenuti nella directory corrente. Sarebbe come se il comando fosse ls microinterruttore microscopico...
In tal senso, anche il comportamento di ls cambia: non si limita a elencare il contenuto della directory corrente, ma (eventualmente, se ce ne sono) anche quello di tutte le directory contenute in quella corrente.
L'asterisco può essere utilizzato anche assieme a parti fisse di testo.
$ ls micro*[Invio]
Questo comando è composto in modo che la shell sostituisca micro* con tutti i nomi che iniziano per micro.
microinterruttore microscopico |
È stato precisato che l'asterisco può essere sostituito anche con la stringa nulla. Per verificarlo si crea un altro file.
$ touch nanomicro[Invio]
Con il comando seguente si vogliono elencare tutti i nomi che contengono la parola micro.
$ ls *micro*[Invio]
microinterruttore microscopico nanomicro |
Il punto interrogativo rappresenta esattamente un carattere qualsiasi.
Prima di proseguire si aggiungono alcuni file con nomi adatti agli esempi seguenti.
$ touch xy123j4[Invio]
$ touch xy456j5[Invio]
$ touch xy789j111[Invio]
$ touch xy78j67[Invio]
Con il comando seguente si vuole intervenire su tutti i file lunghi esattamente sette caratteri che contengono la lettera j nella sesta posizione.
$ ls ?????j?[Invio]
xy123j4 xy456j5 |
Diverso sarebbe stato usando l'asterisco: non si può limitare il risultato ai file che contengono la lettera j nella sesta posizione, ma nemmeno la lunghezza del nome può essere presa in considerazione.
$ ls *j*[Invio]
In questo modo si ottiene l'elenco di tutti i nomi che contengono la lettera j, senza specificare altro.
xy123j4 xy456j5 xy789j111 xy78j67 |
Le parentesi quadre vengono utilizzate per delimitare un elenco o un intervallo di caratteri. Rappresentano un solo carattere tra quelli contenuti, o tra quelli appartenenti all'intervallo indicato.
$ ls xy????[4567]*[Invio]
xy123j4 xy456j5 xy78j67 |
Il comando appena indicato è stato scritto in modo da fornire a ls, come argomento, l'elenco di tutti i file i cui nomi iniziano per xy, proseguono con quattro caratteri qualunque, quindi contengono un carattere da 4 a 7 e terminano in qualunque modo. Lo stesso risultato si potrebbe ottenere indicando un intervallo nelle parentesi quadre.
$ ls xy????[4-7]*[Invio]
Il fatto che la shell sostituisca alcuni caratteri impedisce di fatto il loro utilizzo nei nomi di file e directory. Se esiste la necessità, è possibile evitare la sostituzione di questi facendoli precedere da una barra obliqua inversa, che funge da carattere di escape, ovvero, da simbolo di protezione.
$ touch sei\*otto[Invio]
$ ls[Invio]
... sei*otto |
In questo modo è possibile includere nel nome di un file anche lo spazio.
$ touch sei\ bella[Invio]
$ ls[Invio]
... sei bella sei*otto |
È possibile ottenere un risultato simile delimitando il testo che deve essere interpretato come un oggetto unico attraverso apici singoli o apici doppi:
$ touch "sei*sei"[Invio]
$ touch 'tre*due'[Invio]
$ ls[Invio]
... tre*due ... sei bella sei*otto sei*sei |
$ touch "sei alta"[Invio]
$ ls[Invio]
... tre*due ... sei alta sei bella sei*otto sei*sei |
È bene ricordare che l'uso degli apici singoli o degli apici doppi non è sempre equivalente.
L'uso di caratteri jolly può essere pericoloso quando non si ha un'esperienza sufficiente a determinare l'effetto esatto del comando che ci si accinge a utilizzare. Ciò soprattutto quando si utilizzano per cancellare. Il modo migliore per verificare l'effetto della sostituzione dei caratteri jolly è l'uso del comando echo, che si occupa semplicemente di visualizzare l'elenco dei suoi argomenti.
Per esempio, per sapere quali file e directory vengono coinvolti dal modello micro*, basta il comando seguente:
$ echo micro*[Invio]
microinterruttore microscopico |
Anche l'uso di ls, come comando non distruttivo, può essere di aiuto per determinare l'estensione di un modello fatto di caratteri jolly. Ma ls mostra anche il contenuto delle directory che vengono indicate tra gli argomenti, quindi potrebbe distrarre un po' l'utilizzatore.
La shell consente di ridirigere l'output di un comando che normalmente sarebbe destinato allo schermo, oppure di inviare dati all'input di un comando, che altrimenti lo attenderebbe dalla tastiera.
La ridirezione dirotta i dati in modo di destinarli a un file o di prelevarli da un file.
$ ls -l > elenco[Invio]
Questo comando genera il file elenco con il risultato dell'esecuzione di ls. Si può controllare il contenuto di questo file con cat.
$ cat elenco[Invio]
Anche l'input può essere ridiretto, quando il comando al quale si vuole inviare è in grado di riceverlo. cat è in grado di emettere ciò che riceve dallo standard input.
$ cat < elenco[Invio]
Si ottiene in questo modo la visualizzazione del contenuto del file elenco, esattamente nello stesso modo di prima, quando questo nome veniva indicato semplicemente come argomento di cat. Ma adesso lo si invia attraverso lo standard input per mezzo dell'attività della shell.
La ridirezione dell'output, come è stata vista finora, genera un nuovo file ogni volta, eventualmente sovrascrivendo ciò che esiste già con lo stesso nome. Sotto questo aspetto, la ridirezione dell'output è fonte di possibili danni.
La ridirezione dell'output può essere fatta in aggiunta, creando un file se non esiste, o aggiungendovi i dati se è già esistente.
$ ls -l /tmp >> elenco[Invio]
In tal modo viene aggiunto al file elenco l'elenco dettagliato del contenuto della directory /tmp/.
$ cat elenco[Invio]
La pipeline è una forma di ridirezione in cui la shell invia l'output di un comando come input del successivo.
$ cat elenco | sort[Invio]
In questo modo, cat legge il contenuto del file elenco, ma questo, invece di essere visualizzato sullo schermo, viene inviato dalla shell come standard input di sort che lo riordina e poi lo emette sullo schermo.
Una pipeline può utilizzare anche la ridirezione, per cui, il comando visto precedentemente può essere trasformato nel modo seguente:
$ cat < elenco | sort[Invio]
Naturalmente, il comando si può semplificare come indicato sotto, ma in tal caso non si tratta più di pipeline:
$ sort < elenco[Invio]
La creazione di un alias è un metodo che permette di definire un nome alternativo per un comando preesistente.
$ alias elenca='ls -l'[Invio]
Dopo aver definito l'alias elenca, come indicato nel comando precedente, utilizzandolo si ottiene l'equivalente di ls -l. Basta provare.
$ elenca[Invio]
Ma l'alias permette di utilizzare argomenti, come se si trattasse di comandi normali.
$ elenca micro*[Invio]
Quello che si ottiene corrisponde al risultato del comando ls -l micro*:
-rw-rw-r-- 1 tizio tizio 0 Dec 26 10:19 microinterruttore -rw-rw-r-- 1 tizio tizio 0 Dec 26 10:19 microscopico |
Gli alias tipici che vengono creati sono i seguenti. Servono per fare in modo che le operazioni di cancellazione o sovrascrittura vengano eseguite dopo una richiesta di conferma.
$ alias rm='rm -i'[Invio]
$ alias cp='cp -i'[Invio]
$ alias mv='mv -i'[Invio]
Si può provare a eliminare un file per vedere cosa accade.
$ rm microinterruttore[Invio]
rm: remove `microinterruttore'?: |
n[Invio]
In questo modo, il file non è stato cancellato.
Per eliminazione di un alias si procede intuitivamente con il comando unalias:
$ unalias elenca[Invio]
In questo modo, si elimina l'alias elenca in modo selettivo, mentre con il comando seguente si eliminano tutti gli alias ancora esistenti:
$ unalias -a[Invio]
A ogni modo, alla fine della sessione di lavoro con la shell, gli alias vengono perduti.
Il completamento dei nomi e i caratteri jolly sono gli strumenti operativi più importanti che una shell fornisce. Tuttavia, l'uso di modelli con caratteri jolly può essere fonte di errori anche gravi, pertanto, prima di utilizzarli in comandi distruttivi, conviene verificare l'effetto di questi modelli con echo.
La ridirezione e le pipeline sono un altro strumento importante che permette di costruire comandi molto complessi a partire da comandi elementari.
In presenza di un ambiente in multiprogrammazione è importante il controllo dei processi in esecuzione. Un processo è un singolo eseguibile in funzione, ma un comando può generare diversi processi.
Il comando fondamentale per il controllo dei processi è ps.
$ ps x[Invio]
PID TTY STAT TIME COMMAND 077 1 SW 0:01 (login) 078 2 SW 0:01 (login) 091 1 S 0:01 -bash 132 2 S 0:01 -bash 270 1 R 0:00 ps |
In questo caso ps mostra che sono in funzione due copie di bash (la shell Bash), ognuna su un terminale differente (in questo caso si tratta della prima e della seconda console virtuale di un sistema GNU/Linux): TTY 1 e 2. L'unico programma in esecuzione è lo stesso ps, che in questo esempio è stato avviato dal primo terminale.
Attraverso l'opzione f, si può osservare la dipendenza tra i processi.
$ ps xf[Invio]
PID TTY STAT TIME COMMAND 077 1 SW 0:01 (login) 091 1 S 0:01 \_ -bash 275 1 R 0:00 \_ ps -f 078 2 SW 0:01 (login) 132 2 S 0:01 \_ -bash |
In un sistema GNU/Linux esiste il programma pstree che offre un modo graficamente più aggraziato di osservare la dipendenza tra i processi.
$ pstree[Invio]
init-+-crond
|-kflushd
|-klogd
|-kswapd
|-login---bash
|-login---bash---pstree
|-4*[mingetty]
|-4*[nfsiod]
|-portmap
|-rpc.mountd
|-rpc.nfsd
|-syslogd
`-update
|
Mentre prima si vedevano solo i processi connessi ai terminali, adesso vengono visualizzati tutti i processi in funzione in modo predefinito. L'elenco cambia a seconda della configurazione del proprio sistema.
I processi vengono eliminati automaticamente una volta che questi terminano regolarmente. A volte ci può essere la necessità di eliminare forzatamente un processo.
Per verificare questa situazione si può passare sulla seconda console virtuale e da lì avviare un programma inutile che viene poi eliminato attraverso la prima console.
[Alt F2]
Se fosse necessario eseguire l'accesso, è questo il momento di farlo.
$ yes[Invio]
y y y y ... |
Attraverso yes si ottiene un'emissione continua di lettere «y». Si può passare alla prima console e osservare la situazione.
[Alt F1]
$ ps x[Invio]
PID TTY STAT TIME COMMAND 077 1 SW 0:01 (login) 078 2 SW 0:01 (login) 091 1 S 0:01 -bash 132 2 S 0:01 -bash 311 2 R 0:26 yes |
Si decide di eliminare il processo generato da yes attraverso l'invio di un segnale di conclusione.
$ kill 311[Invio]
Il numero 311 è il numero abbinato al processo, o PID, che si ottiene osservando le informazioni emesse da