Scopo principale di questa lezione è di prendere familiarità con la shell di Linux.

Il terminale e la shell

Oggigiorno la maggior parte degli utenti interagisce col computer tramite una interfaccia grafica, basata su menù, finestre e mouse. Una interfaccia di questo tipo si chiama GUI (Graphical User Interface). Ma prima che le interfacce grafiche si diffondessero (diciamo, fino ai primi anni '90) era molto più comune interagire con i computer tramite una interfaccia puramente testuale: l'utente scriveva dei comandi secondo una sintassi specifica, e il computer rispondeva, poi si metteva in attesa di un altro comando. Questo tipo di interfaccia prende il nome di CLI (Command Line Interface).

Il terminale

Sebbene la CLI sia oggi poco usata, tutti i sistemi operativi dispongono di un programma di emulazione terminale, che consente di interagire con il computer secondo il vecchio stile. Il nome esatto di questo programma dipende dal sistema operativo:

  • Windows: Command Prompt e Windows PowerShell (anche Windows Terminal nelle nuove versioni di Windows)
  • macOS: Terminal
  • Linux (con interfaccia GNOME): Terminal, accessibile dal menù Applications → Utilities → Terminal

All'interno del programma di emulazione terminale è possibile eseguire vari programmi che non necessitano (e non sanno come utilizzare) l'interfaccia grafica. La maggior parte dei programmi che scriveremo noi gireranno all'interno dell'emulatore di terminale. In questo momento, però, il programma che ci interessa maggiormente eseguire all'interno del terminale è la shell.

La shell

Il terminale è solo il programma grafico che permette di interagire con il computer tramite comandi testuali. Il vero programma che esegue i comandi si chiama shell. In generale, ogni sistema operativo può avere più di una shell, ma di solito le più comuni sono:

  • Windows: Command Prompt e PowerShell
  • Linux: bash (Bourne-Again SHell)
  • macOS: zsh (Z shell)

Questo è un esempio di bash in esecuzione su Linux:

Esempio di shell linux

A parte l’aspetto grafico, i comandi supportati da una shell cambiano molto da un sistema operativo ad un altro.  Ad esempio, il comando per visualizzare il contenuto di una cartella è:

  • Command promptdir
  • PowerShell: dir oppure ls
  • bash (Linux): ls
  • zsh (macOS): ls

In generale:

  • bash e zsh hanno comandi simili;
  • PowerShell è abbastanza diversa ma ha alcuni comandi simili a bash/zsh;
  • Command Prompt è completamente diverso (e anche oltraggiosamente limitato).

Noi studieremo la bash perché è quella standard di Linux, installata nei computer dell'aula informatica.

Vantaggi della shell

Una volta, prima dell'avvento delle interfacce grafiche, la shell era l'unico mezzo per comunicare con il sistema operativo. Oggi non è più così, ma la shell, per chi la sa usare, conserva ancora dei vantaggi rispetto all'interfaccia grafica:

  • per la maggior parte dei compiti, è più veloce dare un comando con la shell che aprire finestre e finestrelle, anche perché non bisogna mai spostare le mani dalla tastiera per raggiungere il mouse;
  • è programmabile: la shell è  un vero e proprio linguaggio di programmazione con il quale è possibile automatizzare l'esecuzione di vari compiti;
  • alcune attività di basso livello richiedono l'uso della shell, persino in ambiente Windows;
  • è  facilmente utilizzabile da un computer remoto, e in questo modo si ha l'accesso totale alla macchina, che può essere amministrata senza bisogno di essere presenti fisicamente nello stesso luogo.

I primi comandi della shell

Da questo punto della lezione, ci concentreremo sull'uso della shell in Linux.

Non appena lanciate l'applicazione Terminal, appare una finestra con una scritta simile a amato@ai-01:~$, seguita da un blocco quadrato lampeggiante. La scritta prende il nome di prompt mentre il blocco lampeggiante è il cursore. Il prompt vi da alcune informazioni:

  • gamato: è il nome del'utente che sta usando la shell, e corrisponde (di solito) al nome utente con cui avete fatto il login.
  • ai-01: è il nome del computer; i computer in aula informatica si chiamano ai-nn, dove nn è un numero che trovate stampato sul case.
  • ~: indica quale è la cartella corrente (torneremo su questo tra un po').
  • $: indica che state operando come un utente normale. Se foste invece un super-utente, dotato di privilegi particolari per l'amministrazione di sistema, il $ sarebbe sosituito da #.

Dal prompt è possibile digitare i comandi che si vogliono inviare al sistema, utilizzando anche i tasti standard per l'editing: Canc, Ins, Back, Inizio, Fine, , . I tasti e consentono invece di scorrere i comandi già immessi precedentemente, che possono poi essere modificati. Non è possibile usare il mouse per spostare il cursore dentro la finestra del terminale: il mouse lo si può usare solo per selezionare un porzione di testo ai fini delle operazioni di copia e incolla. Una volta che un comando è stato scritto, si deve premere il tasto Invio perché esso venga accettato ed eseguito.

Uno dei comandi più utilizzati con la shell è ls (abbreviazione di LiSt). Il comando ls visualizza il contenuto della cartella corrente:

gamato@ai-01:~$ ls 
AndroidStudioProjects  Desktop    Downloads  knime-workspace  Music            Pictures              Public  snap       Videos
compito.pdf            Documents  Hello.py   lezione          note-231113.txt  problemi-upgrade.txt  R       Templates  xrandr

Quelle in azzurro sono cartelle, quelle in nero dei file veri e propri. Esattamente gli stessi file e cartelle li vedete se aprite l'applicazione Files della GUI (Applications → Accessories → Files). La GUI e la CLI non sono due mondi separati, ma due modi diversi di accedere agli stessi dati. Questo è il risultato:

Contenuto della cartella home in aula informatica.

Se il comando viene scritto in maniera errata, si genera un errore:

gamato@ai-01:~$ lss
Command 'lss' not found, but there are 15 similar ones.

È possibile visualizzare il contenuto di un file con il comando cat (che non ha niente a che fare con i gatti, è l'abbreviazione di conCATenate). Il comando cat ha bisogno però di un parametro, ovvero del nome del file da visualizzare. Il parametro va scritto dopo il comando, separato da spazi. Ad esempio:

gamato@ai-01:~$ cat Hello.py 
print("Hello world.")

La riga print("Hello world.") è il contenuto del file Hello.py. Potete aprire il file anche dalla GUI e vedrete che il contenuto è lo stesso. Ovviamente se il nome del file è sbagliato il sistema dà un errore. In particolare, bisogna stare attenti a scrivere maiuscole e minuscole in maniera corretta, perché per la shell di Linux una lettera minuscola e la corrispondente maiuscola sono due caratteri completamente diversi. Ad esempio il comando cat hello.py fallisce:

gamato@ai-01:~$ cat hello.py
cat: hello.py: No such file or directory

Notare che non tutti i file posono essere visualizzati con cat, solo i cosiddetti file di testo, ovvero file che contengono unicamente testo senza nessun tipo di formattazione. Sono file di testo, ad esempio, i codici sorgente in qualunque linguaggio di programmazione e i file creati con programmi come Text Editor in Linux o Notepad in Windows. Non sono file di testo, ad esempio, documenti in formato Microsoft Office o LibreOffice ed i file PDF.

Se proviamo a visualizzare il contenuto del file compito.pdf con cat otteniamo qualcosa di incomprensibile:

gamato@ai-01:~$ cat compito.pdf
%PDF-1.5
%����
3 0 obj
... e tante altre linee omesse ...

È possibile creare un file vuoto dalla shell con il comando touch FILE. Ad esempio:

gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Downloads  knime-workspace  Music            Pictures              Public  snap       Videos
compito.pdf            Documents  Hello.py   lezione          note-231113.txt  problemi-upgrade.txt  R       Templates  xrandr
gamato@ai-01:~$ touch prova
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Downloads  knime-workspace  Music            Pictures              prova   R     Templates  xrandr
compito.pdf            Documents  Hello.py   lezione          note-231113.txt  problemi-upgrade.txt  Public  snap  Videos
gamato@ai-01:~$ cat prova
gamato@ai-01:~$

Notare che il file prova compare solo nell'output del secondo comando ls, quello dopo il comando touch. Il comando cat non dà errore, ma non visualizza nulla perché il file esiste ma è vuoto. Ovviamente ci sono anche modi per riempire un file con dei contenuti dalla CLI, ma non li vedremo: per questo useremo sempre un programma con interfaccia grafica.

Se vogliamo cancellare un file possiamo usare il comando rm FILE (ReMove):

gamato@ai-01:~$ rm prova
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Downloads  knime-workspace  Music            Pictures              Public  snap       Videos
compito.pdf            Documents  Hello.py   lezione          note-231113.txt  problemi-upgrade.txt  R       Templates  xrandr

Notare che il comando rm è silenzioso, non visualizza nulla, ma ha effettivamente cancellato il file prova, che infatti non compare più nell'elenco dei file.

Se vogliamo copiare un file creandone un duplicato, possiamo usare il comando cp SOURCE DEST (CoPy), che crea un copia del file SOURCE chiamandolo DEST. Se il file DEST esiste già, esso viene rimpiazzato dalla copia di SOURCE. Ad esempio:

gamato@ai-01:~$ cp Hello.py ciao.py
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Hello.py         Music            problemi-upgrade.txt  snap       xrandr
ciao.py                Documents  knime-workspace  note-231113.txt  Public                Templates
compito.pdf            Downloads  lezione          Pictures         R                     Videos
gamato@ai-remote:~$ cat ciao.py 
print("Hello world.")

Vedete che il comando cp ha creato il file ciao.py, con lo stesso contenuto di Hello.py. Se invece vogliamo cambiare nome ad un file, possiamo usare il comando mv SOURCE DEST (MoVe) che cambia il nome del file da SOURCE a DEST. Ad esempio

gamato@ai-01:~$ mv ciao.py ciriciao.py
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Hello.py         Music            problemi-upgrade.txt  snap       xrandr
ciriciao.py            Documents  knime-workspace  note-231113.txt  Public                Templates
compito.pdf            Downloads  lezione          Pictures         R                     Videos

Vedete che dopo l'esecuzione del comando mv il file ciao.py non esiste più, perché il suo nome è cambiato in ciriciao.py.

Comandi e opzioni

A molti dei comandi visti finora è possibile aggiungere delle opzioni per alterarne il funzionamento. Ad esempio, ls può prendere come argomento i seguenti parametri (e tanti altri che qui non cito):

  • -a: visualizza tutti i file, anche quelli nascosti. In Linux un file nascosto è un file che inizia con il punto (a sta per all) 
  • -l : visualizza, per ogni file, un dettaglio dei suoi attributi (lunghezza in byte, data di ultima modifica e informazioni sui diritti di accesso al file)  (l sta per long) 

Quelle che abbiamo visto qua sopra sono le opzioni corte. Esse hanno tutte la stessa forma: il segno meno seguito da una lettera. Alcuni programmi supportano anche delle opzioni lunghe. Ad esempio per ls abbiamo:

  • --all: equivalente a -a
  • --help: visualizza una spiegazione succinta del funzionamento di ls e di tutte le opzioni previste.
  • --version: visualizza la versione del programma ls.

Le opzioni possono essere combinate tra di loro. Ad esempio ls -a -l visualizza tutti i file, compresi quelli nascosti, e visualizza per ognuno i suoi attributi. Stesso risultato dà ls --all -l. Un altro modo di combiare le opzioni corte è usare un unico simbolo - e, in sequenza, le lettere corrispondenti alle varie opzioni. Ad esempio ls -al ha lo stesso effetto di ls -a -l.

Nota. Le opzioni --help e --version sono comuni a molti programmi.

Facciamo qualche esempio. Usiamo ls -a per visualizzare il contenuto della cartella home, compresi tutti i file nascosti:

gamato@ai-01:~$ ls -a
.                      Documents                     Hello.py                      Pictures              Videos
..                     .dotnet                       .ipython                      .pki                  .vscode
.adobe                 Downloads                     .JASP                         problemi-upgrade.txt  .wine
.android               .eclipse                      .java                         .profile              .wireshark
AndroidStudioProjects  .emacs.d                      .knime                        Public                .Xauthority
.aptitude              .emulator_console_auth_token  knime-workspace               .purple               .xchat2
.attach_pid40209       .equo                         .lesshst                      .python_history       .xorgxrdp.10.log
.....omissis.......

Abbiamo troncato l'output perché è troppo lungo. Vedete però che ci sono tantissimi file nascosti. Nella cartella home questo è normale, perché i file (e le cartelle) nascosti contengono la configurazione dei programmi che utilizzate.

Con ls -l otteniamo invece questo risultato: non ci sono i file nascosti, ma i nomi dei file compaiono adesso uno per riga, e ognuno è accompagnato da varie informazioni,

total 868
drwxrwxr-x 10 gamato gamato   4096 ott  1  2023 AndroidStudioProjects
-rw-rw-r--  1 gamato gamato     22 set 21 00:23 ciriciao.py
-rw-rw-r--  1 gamato gamato 189728 set 20 18:22 compito.pdf
drwxr-xr-x  2 gamato gamato   4096 set 11 11:58 Desktop
drwxr-xr-x  3 gamato gamato   4096 set 14 23:42 Documents
drwxr-xr-x  2 gamato gamato   4096 set 11 11:04 Downloads
-rw-rw-r--  1 gamato gamato     22 set 20 13:03 Hello.py
drwxrwxr-x  4 gamato gamato   4096 feb 20  2023 knime-workspace
drwxrwxr-x  2 gamato gamato   4096 set 20 15:09 lezione
drwxr-xr-x  2 gamato gamato   4096 set 28  2022 Music
-rw-rw-r--  1 gamato gamato    569 nov 13  2023 note-231113.txt
drwxr-xr-x  4 gamato gamato   4096 mag 13 17:05 Pictures
-rw-rw-r--  1 gamato gamato 623379 giu 14 19:23 problemi-upgrade.txt
drwxr-xr-x  2 gamato gamato   4096 ott  1  2023 Public
drwxrwxr-x  3 gamato gamato   4096 feb 23  2020 R
drwx------  7 gamato gamato   4096 feb  9  2023 snap
drwxr-xr-x  2 gamato gamato   4096 set 28  2022 Templates
drwxr-xr-x  3 gamato gamato   4096 gen  5  2023 Videos
-rw-r--r--  1 gamato gamato    106 nov 28  2022 xrandr

Cosa è il significato di tutte queste colonne ? 

  • Il primo carattere in ogni riga indica il tipo di file. Trovate d per una directory, - per un file standard. Ci sono altri tipi di file, sebbene poco comuni.
  • I restanti caratteri rwx- indicano i diritti di accesso al file (quali utenti possono accedere a quel file). Tralasciamo questo argomento perché non è al momento di nostro interesse.
  • Il primo dei due gamato è l'utente proprietario del file.
  • Il secondo dei due gamato è il gruppo proprietario del file. Tralasciamo questo argomento perché non è al momento di nostro interesse
  • Il numero successivo è la lunghezza del file in byte.
  • La colonna successiva è la data di ultima modifica del file.
  • L'ultima colonna è il nome del file.

Questo è il riassunto della situazione:

Esercizio 1

Si impara solo sperimentando. Scaricate i file Hello.py e compito.pdf. Se non sono già nella cartella home, spostateli lì usando l'interfaccia grafica. Quindi lanciate il terminale e leggete la sezione "I primi comandi della shell" qui sopra, provando a ripetere in prima persona gli esempi forniti di comandi per la shell.

Cartelle e loro gestione

La memoria di massa di un computer è, come quella principale, una sequenza di byte. Essa è però organizzata in unità più piccole, chiamate file. I file sono a loro volta organizzati in cartelle (in inglese folder o directory), a formare una struttura (chiamata albero) che parte da una directory principale o directory radice e prosegue per varie sotto-directory. Questa ad esempio è un estratto della struttura ad albero di un sistema Linux in aula informatica.


Per avere accesso a directory e file presenti nel computer basta lanciare l'applicazione Files. Quella che viene aperta di default è la home directory dell'utente. Ogni utente ha una home directory, che può gestirsi come vuole, e dove può salvare tutti i propri dati. Modifiche alla propria home directory non influenzano le home directory degli altri utenti. Nei sistemi in stile Unix di solito le home directory si trovano all'interno della directory home. In particolare, in aula informatica, le home directory si trovano dentro la cartella labeconomia, che sta a sua volta dentro la cartella home.

Per uscire dalla home directory e portarsi sulla directory radice, si può cliccare su Other Locations nella barra a sinistra in basso dell'applicazione Files e poi su Computer. Questa è la directory radice vista dall'applicazione Files.

Vediamo ora alcuni comandi per manipolare le cartelle da linea di comando. Nella shell c'è un concetto di directory corrente, che è quella su cui operano i vari comandi. Normalmente la directory corrente è la propria home, che nel prompt è indicata convenzionalmente dal simbolo ~ (tilde). Se vogliamo sapere veramente qual è la cartella corrente nell'albero delle directory, si può usare il comando pwd (Print Working Directory):

gamato@ai-01:~$ pwd
/home/labeconomia/gamato

La scritta /home/labeconomia/gamato indica la cartella a cui si arriva partendo la radice ed entrando successivamente nella cartella home, poi nella cartella labeconomia, infine nella cartella gamato.

Il comand mkdir DIRECTORY (MaKe DIRectory) crea una nuova cartella all'interno della cartella corrente.

gamato@ai-01:~$ mkdir myfolder
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Hello.py         Music            problemi-upgrade.txt  snap       xrandr
myfolder               Documents  knime-workspace  note-231113.txt  Public                Templates
compito.pdf            Downloads  lezione          Pictures         R                     Videos

Possiamo a questo punto entrare nella cartella myfolder usando il comando cd DIRECTORY (Change Directory):

gamato@ai-01:~$ cd myfolder
gamato@ai-01:~/myfolder$

Vedete che dopo il comando cd il prompt è cambiato: dove prima c'era solo la tilde, ad indicare la home directory, adesso c'è ~/myfolder ad indicare che la cartella corrente è la cartella myfolder che si trova dentro la home directory. Se diamo il comando ls, non avendo mai messo nulla dentro questa cartella, non otteniamo nulla:

gamato@ai-01:~/myfolder$ ls
gamato@ai-01:~/myfolder$ touch pippo
gamato@ai-01:~/myfolder$ ls
pippo

Se vogliamo salire di un ramo nell'albero delle directory, si può usare la sintassi speciale cd .. (cd seguito da due caratteri punto). 

gamato@ai-01:~/myfolder$ cd ..
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Hello.py         Music            Pictures              R          Videos
ciriciao.py            Documents  knime-workspace  myfolder         problemi-upgrade.txt  snap       xrandr
compito.pdf            Downloads  lezione          note-231113.txt  Public                Templates

Notare che c'è un altro modo per visualizzare il contenuto di una cartella senza bisogno di entrarci dentro, che è tramite il comando ls con un parametro aggiuntivo che specifica la cartella da visualizzare:

gamato@ai-01:~$ ls myfolder/
pippo

Per cambiare nome ad una cartella possiamo usare lo stesso comando mv visto per i file:

gamato@ai-01:~$ mv myfolder miacartella
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Hello.py         miacartella      Pictures              R          Videos
ciriciao.py            Documents  knime-workspace  Music            problemi-upgrade.txt  snap       xrandr
compito.pdf            Downloads  lezione          note-231113.txt  Public                Templates

Vedete che la cartella myfolder è ora diventata miacartella.

È possibile anche copiare una cartella creandone un duplicato usando il comando cp con l'opzione -r (che sta per recursive, un termine che impareremo a conoscere):

gamato@ai-01:~$ cp -r miacartella miacartella2
gamato@ai-01:~$ ls
AndroidStudioProjects  Desktop    Hello.py         miacartella   note-231113.txt       Public  Templates
ciriciao.py            Documents  knime-workspace  miacartella2  Pictures              R       Videos
compito.pdf            Downloads  lezione          Music         problemi-upgrade.txt  snap    xrandr
gamato@ai-01:~$ ls miacartella
pippo
gamato@ai-01:~$ ls miacartella2
pippo

Infinte, se si vuole cancellare una cartella, si può usare il comando rmdir CARTELLA(ReMove DIRectory). È importante però che la CARTELLA sia vuota, altrimenti il comando fallisce.

gamato@ai-remote:~$ rmdir miacartella2
rmdir: failed to remove 'miacartella2': Directory not empty
gamato@ai-remote:~$ ls miacartella2
pippo
gamato@ai-remote:~$ rmdir miacartella2
rmdir: failed to remove 'miacartella2': Directory not empty
gamato@ai-remote:~$ cd miacartella2
gamato@ai-remote:~/miacartella2$ ls
pippo
gamato@ai-remote:~/miacartella2$ rm pippo
gamato@ai-remote:~/miacartella2$ cd ..
gamato@ai-remote:~$ rmdir miacartella2
gamato@ai-remote:~$ ls
AndroidStudioProjects  Documents  knime-workspace  Music            problemi-upgrade.txt  snap       xrandr
compito.pdf            Downloads  lezione          note-231113.txt  Public                Templates
Desktop                Hello.py   miacartella      Pictures         R                     Videos

Le cartelle speciali . e ..

Se visualizziamo tutti i file presenti in una cartella con ls -a vedremo che troviamo sempre due cartelle speciali. Questo ad esempio è il contenuto della directory miacartella.

gamato@ai-01:~$ cd miacartella
gamato@ai-01:~/miacartella$ ls -a . .. pippo

La cartella . (punto) indica la cartella visualizzata (ovvero miacartella), mentre .. indica la cartella da cui si proviene nell'albero delle directory (ovvero la cartella home). Pertanto, il comando cd . non ha assolutamente alcun effetto (rimane nella cartella corrente), mentre cd .. risale l'albero delle directory, come già visto.

gamato@ai-01:~/miacartella$ cd .
gamato@ai-01:~/miacartella$ cd ..
gamato@ai-01:~$ 

Esercizio 2

Vi ripeto che si impara solo sperimentando. Leggete la sezione "Cartelle e loro gestione" qui sopra, provando a ripetere in prima persona gli esempi forniti di comandi per la shell.

Percorsi assoluti e relativi

Abbiamo visto che molti comandi hanno come argomento un nome di file. Ma che struttura ha un nome di file Linux? Nel vecchio sistema operativo DOS, il nome aveva una struttura fissa di 8 caratteri, un punto, e altri 3 caratteri (detti estensione). L'estensione serviva a identificare il tipo di file: .jpg per file immagini JPEG, .txt per file di testo puri, .doc per file Word, etc..

Nei sistemi operativi moderni un nome di file è una stringa di caratteri qualunque, e può contenere quanti punti si desidera (anche nessuno). L'estensione non è necessaria, ma spesso la si aggiunge per facilitare la vita all'utilizzatore del computer, che così è in grado di riconoscere il tipo di ogni file. Anche alcuni programmi si basano sull'estensione di un file per decidere come trattarlo. Notare che ormai l'estensione può anche essere più lunga di 3 caratteri: ad esempio .java è l'estensione standard per i file sorgente Java.

Tuttavia, specificare semplicemente il nome di un file non è sufficiente. Infatti, all'interno del file system possono esserci molti file con lo stesso nome, ma che stanno in directory diverse. Come si fa, allora, a indicare con esattezza un file specifico, in modo che non sorgano ambiguità? Bisogna utilizzare i pathname (nomi dei percorsi) che possono essere di due tipi: assoluti o relativi.

Percorso assoluto

Un percorso assoluto è una stringa del tipo:

     /DIRECTORY/DIRECTORY/DIRECTORY/FILE

che inizia con la barra di divisione, ha una serie di componenti separati da barre e termina con un nome di file. La sequenza delle varie componenti DIRECTORY è la sequenza di cartelle dentro le quali il sistema deve entrare, partendo dalla radice, per raggiungere la cartella dove si trova il file desiderato. Ad esempio:

  • /home/amato/prova.txt si riferisce a un file prova.txt nella home directory di gamato.
  • /abcd si riferisce a un file di nome abcd (senza estensione) dentro la directory radice.

Sono importanti alcune cose:

  • il percorso assoluto deve iniziare con la barra di divisione;
  • la barra da utilizzare è quella per la divisione (/) e non la barra retroversa (\) che si usa invece nei sistemi Windows;
  • è necessario specificare la sequenza completa di tutte le directory da attraversare per arrivare al file desiderato.

Percorso relativo

Ogni processo (programma in esecuzione) in Linux ha una directory corrente.  Quando si specifica un nome di file direttamente, senza percorso, il file viene cercato in questa directory. Abbiamo visto che per cambiare directory corrente nella shell di Linux, si può usare il comando cd. Più in generale, la directory corrente serve come punto di riferimento per i percorsi relativi.

Un percorso relativo è una stringa di questo tipo:

     DIRECTORY/DIRECTORY/DIRECTORY/FILE

quindi è simile a un percorso assoluto ma non ha la barra iniziale. Anche il significato è simile a quello di un percorso assoluto, con la differenza che la directory da cui iniziare la ricerca del file non è la directory radice ma la directory corrente. Ad esempio, se la directory corrente è /home, allora:

  • amato/prova.txt si riferisce a un file prova.txt nella home directory di amato.
  • ../abcd si riferisce a un file di nome abcd (senza estensione) dentro la directory radice.

Di solito ovunque si può inserire il nome di un file, si può inserire un percorso assoluto o relativo. Ma quale conviene usare tra i due? Quando si usa la shell in maniera interattiva, come facciamo noi in questa lezione, si può usare quello che ci torna più comodo. Quando però si scrivono dei programmi che hanno bisogno di accedere a vari file ad essi correlati, è meglio utilizzare percorsi relativi. In questo modo, sarà poi più facile spostare tutto il software da una directory ad un altra senza comprometterne il funzionamento.

Ad esempio, supponiamo di aver scritto un programma vis che ha bisogno di alcune immagini per funzionare. Decidiamo di mettere il programma vis nella directory /home/amato/prg e le immagini in una sottodirectory, ad esempio /home/amato/prg/img. Quando nel programma abbiamo bisogno di riferirci ad una immagine, è meglio se usiamo un percorso relativo alla directory /home/amato/prg. Così, l'immagine titolo.jpg dovrà essere riferita con il percorso img/titolo.jpg. In questo modo, quando ci porteremo il programma a casa nel nostro computer, potremo decidere di mettere il tutto (il programma vis e la sottodirectory img) nella directory /usr/local/mioprog e il programma continuerà a funzionare a dovere. La vecchia immagine /home/amato/prg/img/titolo.jpg non esiste più, ma al suo posto abbiamo /usr/local/mioprog/img/titolo.jpg e, partendo da /usr/local/mioprog il percorso relativo img/titolo.jpg  punta propro a quest'ultima. Torneremo su questo punto quando vedremo come manipolare i file dal linguaggio Python.

Operare con percorsi assoluti e relativi dalla CLI

Nei comandi della CLI, tutte le volte che compare un nome di file si può invece mettere un percorso assoluto o relativo.

Ad esempio il comando cp Hello.py miacartella/Ciao.py copia il file Hello.py che si trova nel file Ciao.py dentro la cartella miacartella.

gamato@ai-01:~$ cp Hello.py miacartella/Ciao.py
gamato@ai-01:~$ cat miacartella/Ciao.py 
print("Hello world.")

Se nel percorso destinazione si omette il nome del file, esso viene copiato con lo stesso nome che aveva nella cartella originaria.

gamato@ai-01:~$ cp Hello.py miacartella
gamato@ai-01:~$ ls miacartella
Ciao.py  Hello.py  pippo

Vediamo che in miacartella si trovano tre file: pippo (creato inizialmente con il comando touch), Ciao.py (copiato prima) e Hello.py (copiato adesso).  Analogamente si può usare il comando mv per spostare un file da una cartella ad un'altra:

gamato@ai-remote:~$ ls
AndroidStudioProjects  Desktop    Hello.py         miacartella   note-231113.txt       Public  Templates
ciriciao.py            Documents  knime-workspace  miacartella2  Pictures              R       Videos
compito.pdf            Downloads  lezione          Music         problemi-upgrade.txt  snap    xrandr
gamato@ai-remote:~$ mv ciriciao.py miacartella
gamato@ai-remote:~$ ls
AndroidStudioProjects  Documents  knime-workspace  miacartella2     Pictures              R          Videos
compito.pdf            Downloads  lezione          Music            problemi-upgrade.txt  snap       xrandr
Desktop                Hello.py   miacartella      note-231113.txt  Public                Templates
gamato@ai-remote:~$ ls miacartella
Ciao.py  ciriciao.py  Hello.py  pippo

Si vede che col comando mv il file Hello.py è sparito dalla cartella home ed è stato spostato in miacartella.

Esercizio 3

Si consideri la seguente struttura ad albero:

Scrivere i percorsi relativi ed assoluti per i file f1, f2, f3 e per le directory atena e zeus, nei due casi in cui la directory corrente è opt o atena.

Varie ed eventuali

Comandi e programmi

La maggior parte di quelli che abbiamo chiamato comandi della shell sono in realtà programmi veri e propri che la shell si limita a lanciare. Ad esempio, cp è un programma, il cui percorso completo è /usr/bin/cp. Dalla shell è possibile lanciare non solo i comandi, ma anche programmi più sofisticati e con interfaccia grafica. Ad esempio, se si vuole modificare il file Hello.py, è possibile apririle dalla GUI, ma in alternativa è possibile lanciare dalla shell l'editor di testo fornendo come parametro il nome del file da modificare. Ad esempio:

gamato@ai-01:~$ gedit Hello.py

In questo comando gedit è l'editor per file di testo standard di Linux (un po' come il Notepad di Windows). La shell chiama il programma gedit che quindi apre una finestra grafica con il contenuto del file specificato. Notare che la shell è sospesa, non accetta più nessun input, finché il programma gedit è in esecuzione.

Completamento automatico

Una caratteristica utile della shell di Linux è il completamente automatico. In varie circostante potete premere il tasto Tab e la shell completa quello che state scrivendo nella maniera più ovvia. Il tasto Tab (tabulazione) si trova quasi sempre a sinistra, sotto la barra retroversa (\), e su di esso sono disegnate due frecce puntate in direzioni opposte. Ad esempio, se siete nella situazione

gamato@ai-01:~$ pass

e premete Tab, la stringa pass viene completata in passwd (il comando per cambiare la propria password). Questo perché passwd è l'unico comando che inizia con pass. Analogamente, se nella directory corrente c'è il file "Hello.py" e voi premete Tab quando avete digitato

gamato@ai-01:~$ cat He

allora He viene completato in Hello.py. In generale, quasi su ogni sistema è vero quanto segue:

  • se premete Tab; sulla prima parola di una riga di comando, la shell tenta di completare la stringa immessa con un comando valido;
  • se premete Tab sulle parole successive alla prima in una riga di comando, la shell tenta di completare la stringa con un nome di file valido.

Talvolta premendo Tab non succede niente: vuol dire che c'è ambiguità nel modo in cui si può completare la stringa. Ad esempio, se abbiamo anche il file Herr oltre a Hello.py, premere Tab dopo He è ambiguo perché He potrebbe essere completato in due modi diversi.

In questo caso, si può premere Tab due volte di seguito per avere l'elenco dei possibili completamenti. Ad esempio, con

gamato@ai-01:~$ rm

premendo TabTab si ha l'elenco dei comandi che iniziano con rm:

gamato@ai-remote:~$ rm
rm           rmdir        rmic         rmid         rmiregistry  rmmod        rmt          rmt-tar      

Il Tab può essere usato per spostarsi velocemente nell'albero delle directory. Se si vuole visualizzare il file /proc/cpuinfo (che contiene informazioni sulla CPU usata dal computer) il comando da dare è cat /proc/cpuinfo. Si può scrivere questo comando molto più velocemente digitando:

cat /pTab/cpTab

La funzione di completamento automatico è veramente comoda. Una volta che ci si è famirializzato, è difficile farne a meno.

Nomi dei file con spazi

Se un nome dei file contiene uno spazio, e lo si deve specificare nella shell, va racchiuso tra apici o virgolette, altrimenti la shell pensa che si tratti di due file diversi. Ad esempio, se si vuole creare un file vuoto dal nome Galileo Galiei non si può usae il comando touch Galileo Galilei, perché questo creerebbe due file: uno di nome Galileo, l'altro di nome Galilei. Il comando corretto da usare è touch 'Galileo Galilei'.

Immissione caratteri speciali

Spesso è necessario inserire dei caratteri che non sono presenti nella tastiera. Come si fa in questo caso? Il trucco tipico di Windows (Alt+il codice ASCII sul tastierino numerico) su Linux non funziona. In realtà, i caratteri più comuni possono essere digitati con alcune combinazioni di tasti standard:

  • AltGr + apostrofo = apice
  • AltGr + ì = ~
  • AltGr + e = €
  • AltGr + é = ShiftAltGr + è = {
  • AltGr + * = ShiftAltGr + più = }

Per chi non lo sapesse, il tasto Shift è quello che si usa per fare le maiuscole, tavolta indicato con Maiusc nelle tastiere italiane, mentre  AltGr è il tasto Alt posto a destra della barra spaziatrice.

Un'altra combinazione da sapere è quella per copiare e incollare nel terminale. Mentre di solito le combinazione per copiare e incollare sono Ctrl + C e Ctrl + V rispettivamente, queste combinazioni non funzionano nel terminale perché hanno un altro significato. Al loro posto, è possibile usare Ctrl + Maiusc + C e Ctrl + Maiusc + V.

Il manuale in linea

Nessuno è ingrado di ricordare tutti i possibili comandi e le differenti opzioni disponibili in ambiente Unix. Per fortuna la documentazione in materia è estensiva. Abbiamo già visto l'opzione --help che è possibile fornire a molti comandi per farci restituire la spiegazione del suo funzionamento e delle opzioni che supporta. La spiegazione che si ottiene è però spesso troppo stringata, utile quando il comando lo si conosce già e semplicemente non ci si ricorda il formato di qualche opzione, ma non quando si vuole imparare come utilizzarlo.

Per quest'ultimo scopo è molto più utile il comando man COMANDO (manual). Ad esempio, esempio man rmdir visualizza il manuale del comando rmdir, che vedete qui sotto:

RMDIR(1)                                                User Commands                                               RMDIR(1)

NAME
       rmdir - remove empty directories

SYNOPSIS
       rmdir [OPTION]... DIRECTORY...

DESCRIPTION
       Remove the DIRECTORY(ies), if they are empty.

       --ignore-fail-on-non-empty

              ignore each failure that is solely because a directory

              is non-empty

       -p, --parents
              remove DIRECTORY and its ancestors; e.g., 'rmdir -p a/b/c' is similar to 'rmdir a/b/c a/b a'

       -v, --verbose
              output a diagnostic for every directory processed

       --help display this help and exit

       --version
              output version information and exit

AUTHOR
       Written by David MacKenzie.

REPORTING BUGS
       GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
       Report any translation bugs to <https://translationproject.org/team/>

La lettura del manuale non è sempre agevole e bisogna abituarsi un po', anche perché spesso le spiegazioni sono molto tecniche. Le sezioni più importanti sono:

  • NAME: il nome del comando e una sua descrizione breve (che sta in una sola riga)
  • SYNOPSIS: la sintassi del comando. È importante conoscere alcune convenzioni utilizzate in questa sezione. 
    • I tre puntini (...) stanno ad indicare che il parametro precedente può essere ripetuto più volte (separando i vari elementi da spazio). Quindi, se voglio cancellare le cartelle c1 e c2, posso dare il comando rmdir c1 c2.
    • Quello che sta tra parentesi quadre è opzionale: si può mettere, ma non è necessario. La parentesi quadre stesse non vanno mai inserite nel comando ! Quindi la stringa [OPTION]... vuol dire che dopo il nome del comando è possibile, facoltativamente, indicare una o più opzioni. Notare che invece almeno una directory deve essere presente perché il parametro DIRECTORY non è racchiuso tra parentesi quadre. Ad esempio, il comando rmdir -p c1/c2 cancella la cartella c2 (che si trova dentro c1) e poi c1 stessa (supponendo che per il resto queste due cartelle siano tutte vuote). Normalmente la cartella c1 non verrebbe cancellata, è l'opzione -p che causa questo comportamento.
    • Alcune opzioni sono disponibili sia in forma breve che in forma lunga: le due forme vengono mostrate una accanto all'altra. Ad esempio, una alternativa a rmdir -p c1/c2 è rmdir --parents c1/c2.
  • DESCRIPTION: spiega cosa fa il comando e il significato di tutte le opzioni disponibili.

Esercizi riassuntivi

Esercizio 4

Visualizzare il contenuto del file /proc/cpuinfo.

Esercizio 5

Esaminare l'elenco delle periferiche PCI presenti nel sistema eseguendo il programma lspci.

Esercizio 6

Utilizzando i comandi della shell, creare all'interno della vostra home directory una cartella dal nome prova e, dentro quest'ultima, una ulteriore cartella dal nome prova-nidificata. Creare dentro prova-nidificata un file di testo di nome provatesto.txt con un contenuto a piacere (come editor di testi si può usare il programma Text Editor). Controllare che il contenuto sia leggibile usando il comando cat. A questo punto spostare il file provatesto.txt nella directory prova con il nuovo nome provatesto2.txt, e cancellare la directory prova-nidificata.

Esercizio 7

Questo esercizio è da considerare la continuazione dell'esercizio precedente.

Creare la directory prova-nidificata2 dentro la directory prova e prova-nidificata3 dentro prova-nidificata2. Creare un file di testo prova-file dentro prova-nidificata3 con un contenuto a piacere. Il metodo standard che abbiamo visto per cancellare unaa irectory dalla shell è quello di cancellare prima i file che essa contiene con rm e poi la cartella stessa con rmdir. Senza seguire questa procedura, consultare la documentazione sul comando rm e capire come cancellare, con un unico comando, la directory prova e tutte le sue sottodirectory.

Last modified: Sunday, 10 November 2024, 5:16 PM