Microsoft's Internet Explorer browser has no built-in vector graphics machinery required for "loss-free" gradient background themes.

Please upgrade to a better browser such as Firefox, Opera, Safari or others with built-in vector graphics machinery and much more. (Learn more or post questions or comments at the Slide Show (S9) project site. Thanks!)

Amministrazione di Sistemi GNU/Linux

04 - Shell e linea di comando

ITIS MEDI

Obiettivi

  • CLI come potente paradigma UI: le shell Unix
  • Comandi della shell – cosa sono, come funzionano
  • Posizione dei comandi nel sistema
  • Documentazione di sistema
  • HW di sistema
  • Gestione del FS
  • Processi
  • Environment
  • Flussi dati, standard I/O, pipes, comandi per lo stream processing

La shell 1/2

In termini generali una shell è un software fornisce una interfaccia di interazione ad un utente.

Le shell si dividono in due grandi tipologie:

Nell’ambito dell’amministrazione di sistema, la shell è l’applicazione che interpreta i comandi dell’amministratore attraverso un interfaccia testuale.

La shell 2/2

La shell è uno strumento molto potente e insostituibile per l’amministratore di sistema. Tramite la shell è possibile gestire il le componenti più interne del sistema in modo molto più potente ed efficace rispetto alle interfacce grafiche:

NOTA: Il termine shell (guscio) sta ad indicare la proprietà di una shell di porsi come intermediario tra l’utente e i meccanismi interni del sistema, facilitandone la gestione.

Shell Unix

Nel mondo Unix esistono diverse implementazioni di shell. Le più usate sono:

Ogni shell si distingue per il tipo di funzionalità, per la sintassi utilizzata, per le risorse richieste.

Nel seguito del nostro corso faremo riferimento alla più utilizzata in assoluto: Bourne Again shell ( bash )

La shell bash è una shell compatibile con sh con la quale condivide molte funzionalità.

La shell bash può essere controllata attraverso l’interazione diretta con un terminale o attraverso dei veri e propri programmi ( script ) in grado di eseguire compiti complessi.

La linea di comando

L’interazione con una shell avviene attraverso la linea di comando di un terminale.

Il terminale è un software all’interno del quale è in esecuzione una shell.

Generalmente, la linea di comando di un terminale corrisponde con l’ultima riga attiva dello schermo (o della finestra) all’interno del quale è in esecuzione il terminale.

andrea@ganimoide:~$

Nel riquadro sopra viene mostrato il prompt della linea di comando di una shell bash. Il prompt è un testo che segnala all’utente che la shell è pronta a ricevere i suoi comandi. Nel caso specifico, il prompt della shell bash indica di solito (se non è stato personalizzato):

Comandi

Come abbiamo visto, una shell è un’interprete di comandi.

Un comando è un’operazione richiesta al sistema.

Tecnicamente, un comando è di solito costituito da un programma eseguibile che viene richiamato direttamente dall’utente della shell oppure da un altro comando/processo.

L’utente interagisce con il sistema attraverso i comandi. La shell funge da intermediario di questa interazione.

Inviare un comando alla shell

Per inviare un comando ad una shell bash occorre:

andrea@ganimoide:~$ ls
Documenti Immagini  Modelli  Musica  Pubblici  Scrivania Video

Il riquadro mostra il risultato (o output) prodotto dall’invio del comando ls.

Due funzionalità molto utili delle shell moderne sono la cosidetta TAB completion e la history.

La funzione di TAB completion consente all’utente di completare il comando senza bisogno di scriverlo per intero ma semplicemente premendo il tasto TAB.

La history permette invece di richiamare in maniera veloce gli ultimi comandi inseriti.

Radiografia di un comando: argomenti e opzioni

Nella slide precedente abbiamo eseguito il comando ls nel modo più semplice possibile: chiamandolo per nome.

Generalmente, le funzionalità di un comando possono essere estese invocandolo con argomenti e opzioni.

ls [OPTION]... [FILE]...

Nel riquadro è riportata la sintassi del comando ls.

Al posto di [OPTION] si indicano le opzioni da passare al comando.

Al posto di [FILE] si indicano gli argomenti da passare al comando.

andrea@ganimoide:~/Documenti/books$ ls -l *.gz
-rw-r--r-- 1 andrea andrea 299419 2009-01-12 12:11 bash-intro.pdf.gz

Nel riquadro sopra si vede l’output di ls ottenuto passando al comando l’opzione -l e l’argomento *.gz.

Argomenti di un comando 1/2

Gli argomenti rendono un comando flessibile e ne ampliano le funzionalità.

Ad esempio, l’argomento *.gz passato al comando ls specifica l’estensione dei file che devono essere elencati (cioè tutti i file con estensione gz ):

andrea@ganimoide:~/Documenti/books$ ls -l *.gz
-rw-r--r-- 1 andrea andrea 299419 2009-01-12 12:11 bash-intro.pdf.gz

Il comando mv nel riquadro sotto rinomina il file con nome vecchio_nome in un file con nome nuovo_nome.

andrea@ganimoide:~$ mv vecchio_nome nuovo_nome

vecchio_nome e nuovo_nome sono i gli argomenti passati al comando mv.

Il comando cp nel riquadro sotto copia tutti i file della cartella Documenti nella cartella backup:

andrea@ganimoide:~$ cp Documenti/* backup/

Documenti/* e backup/ sono gli argomenti passati al comando cp.

Argomenti di un comando 2/2

Come si intuisce, molti comandi necessitano di uno o più argomenti per funzionare correttamente.

Questi argomenti si dicono obbligatori.

Esistono almeno due convenzioni per individuare gli argomenti obbligatori all’interno della sintassi di un comando:

Ad esempio, la sintassi del comando cp è:

cp [OPTION]... SOURCE... DIRECTORY

Come si vede gli argomenti SOURCE e DIRECTORY sono obbligatori in quanto non compaiono tra parentesi quadre.

Opzioni di un comando

A differenza degli argomenti, le opzioni passate ad un comando non sono (generalmente) indispensabili al funzionamento dello stesso.

Come gli argomenti, anche le opzioni amplificano o modificano le funzionalità di un comando.

Ad esempio l’opzione -l passata al comando ls modifica la formattazione del risultato (i file vengono elencati sotto forma di elenco).

Le opzioni possono essere anche combinate tra loro.

Ad esempio, per visualizzare i file di una cartella sotto forma di elenco e ottenere le dimensioni degli stessi in byte e multipli di byte occorre utilizzare contemporaneamente le opzioni -l e -h:

andrea@ganimoide:~/src/wordchallenger/spec$ ls -lh
totale 8,0K
-rwx------ 1 andrea andrea   25 2008-12-09 20:32 spec.opts
-rwx------ 1 andrea andrea 1,4K 2008-12-11 11:50 wordchallenger_spec.rb

Nota che lo stesso comando può essere inviato anche tenendo le opzioni separate:

andrea@ganimoide:~/src/wordchallenger/spec$ ls -l -h

Sintassi di un’opzione

Come si nota dagli esempi presentati finora, l’interprete dei comandi è in grado di discernere un argomento da un’opzione in base alla presenza del carattere - (trattino) preposto prima del nome di quest’ultima.

Inoltre, esistono due diversi formati per i nomi delle opzioni:

Il formato corto è quello utilizzato finora nei nostri esempi.

Il formato lungo, dove supportato, rende il comando più “leggibile”. Il formato lungo è denotato dai caratteri -- (due trattini) preposti al nome dell’opzione.

Molte opzioni supportano entrambi i formati.

Riproponiamo l’esempio del comando ls utilizzando, per le opzioni, i formati lunghi (dove supportati):

andrea@ganimoide:~/src/wordchallenger/spec$ ls -l --human-readable
totale 8,0K
-rwx------ 1 andrea andrea   25 2008-12-09 20:32 spec.opts
-rwx------ 1 andrea andrea 1,4K 2008-12-11 11:50 wordchallenger_spec.rb

Opzioni comuni

Ci sono delle opzioni la cui funzione è nota per convenzione.

Ad esempio, se vogliamo conoscere la sintassi di utilizzo di un comando, passeremo allo stesso l’opzione --help (oppure -h):

andrea@ganimoide:~$ ls --help
Uso: ls [OPZIONE]... [FILE]...
Elenca informazioni sui FILE (predefinito: la directory corrente).
Ordina alfabeticamente le voci se non è usato uno di -cftuvSUX oppure --sort.

Gli argomenti obbligatori per le opzioni lunghe lo sono anche per quelle brevi.
  -a, --all                  non nasconde le voci che iniziano con .
...

Altre opzioni comuni sono:

Altre ancora si possono trovare qui

Alcuni esempi

Oltre agli esempi di comando mostrati nelle precedenti slide, ne proponiamo degli altri:

Copia ricorsiva di una cartella in un’altra

cp -r cartella_sorgente/* cartella_destinazione/ 

Visualizzazione del contenuto di un file sul terminale

cat file

Visualizzazione del contenuto di un file sul terminale con impaginazione

less file

Decompressione di un archivio compresso (tarball) con algoritmo gzip

tar -xvzf archivio.tar.gz

Localizzare un comando

Per conoscere la posizione all’interno del filesystem di un comando la shell mette a disposizione una serie di strumenti.

Il comando which localizza i percorsi in cui si trovano i file binari relativi ad un comando (o ad una lista di comandi).

andrea@ganimoide:~$ which gcc ruby java
/usr/bin/gcc
/usr/bin/ruby
/usr/bin/java

Il comando whereis localizza i percorsi dei file binari, della documentazione e del codice sorgente relativi ad un comando (o ad una lista di comandi).

andrea@ganimoide:~$ whereis gcc ruby java
gcc: /usr/bin/gcc /usr/lib/gcc /usr/share/man/man1/gcc.1.gz
ruby: /usr/bin/ruby /usr/bin/ruby1.8 /usr/lib/ruby /usr/share/man/man1/ruby.1.gz
java: /usr/bin/java /etc/java /usr/share/java /usr/share/man/man1/java.1.gz

Documentazione di Sistema 1/2

Per uno uso proficuo del terminale è fondamentale saper reperire la documentazione relativa ai comandi.

La shell mette a disposizione una serie di comandi orientati alla visualizzazione e alla navigazione della documentazione.

Il comando man visualizza le pagine di manuale relative ad una particolare voce (comando, funzione o programma) e permettere di navigarle attraverso un’interfaccia di testo.

Ad esempio, se si prova a digitare

andrea@ganimoide:~$ man ls

il comando visualizzerà le pagine di manuale del comando ls all’interno della finestra del terminale.

Il comando info è un lettore di manuali scritti in formato Texinfo.

Il formato Texinfo permette la stesura articolata di documentazione.

andrea@ganimoide:~$ info ls

Documentazione di Sistema 2/2

Generalmente, la documentazione redatta in formato Texinfo è più completa rispetto a quella accessibile tramite il comando man.

Per visualizzare le pagine di documentazione di un comando è sufficiente invocare info seguito dal nome del comando:

andrea@ganimoide:~$ info ls

Un altro comando utile nella ricerca di documentazione è apropos.

apropos effettua una ricerca per parola chiave all’interno di tutti i manuali presenti nel sistema.

andrea@ganimoide:~$ apropos ruby
erb (1)              - an embedded Ruby language interpreter
erb1.8 (1)           - an embedded Ruby language interpreter
irb1.8 (1)           - interactive ruby
...

Infine, un’altra fonte di informazioni presente nel sistema è la cartella /usr/share/doc. Generalmente, in questa cartella le applicazioni installano la propria documentazione.

Interrogare le componenti hardware del sistema

Per gestire opportunamente il sistema è necessario poter accedere alle informazioni riguardanti le componenti hardware dello stesso. La shell offre una serie di comandi utili a questo scopo.

Il comando lsusb, ad esempio, visualizza l’elenco di tutte le periferiche usb connesse al sistema.

Analogamente, il comando lspci visualizza i dettagli hardware delle schede con slot PCI installate nel sistema.

Inoltre, una preziosa fonte di informazione è costituita dalla cartella /proc/ che contiene, sotto forma di file, una serie di informazioni utili relative alla componentistica elettronica del sistema.

Ad esempio il comando

andrea@ganimoide:~$ cat /proc/cpuinfo

visualizza informazioni dettagliate circa il processore (o i processori) presenti nel sistema.

Infine, il comando fdisk (eseguito con i permessi di amministratore) riporta le informazioni riguardanti i supporti di memorizzazione presenti.

andrea@ganimoide:~$ sudo fdisk -l

Gestire file e cartelle

Naturalmente, la shell offre un insieme di comandi che permettono un’agevole navigazione all’interno del filesystem (fs).

Come vedremo in seguito, il fs rappresenta la struttura con la quale i dati vengono rappresentati nel sistema.

In un tipico fs GNU/Linux non esiste differenza tra file e cartelle: ogni elemento del fs è un file:

Tuttavia, nel seguito della lezione, per semplicità di esposizione, faremo distinzione tra file e cartelle.

La struttura delle cartelle all’interno del fs è una struttura gerarchica. Per avere un’idea della struttura di un tipico fs GNU/Linux digitate:

ls -l /

Il risultato ottenuto rappresenta il contenuto della cartella principale (/).

Navigare all’interno del filesystem 1/2

Il comando che si utilizza per spostarsi da una cartella ad un’altra è cd.

andrea@ganimoide:~$ cd Documenti
andrea@ganimoide:~/Documenti$ 

Ad esempio, nel riquadro sopra si sta invocando il comando cd insieme all’argomento Documenti. Il risultato dell’esecuzione del comando si vede al prompt della linea successiva che indica la cartella in cui ci si trova dopo lo spostamento.

Il simbolo di ~ (tilde) è una forma contratta che sta ad indicare la cartella home dell’utente che sta operando sul terminale (/home/andrea/).

Il comando pwd segnala la posizione attuale all’interno del fs:

andrea@ganimoide:~/Documenti$ pwd
/home/andrea/Documenti

Come si vede il comando pwd ha espanso la forma contratta ~/Documenti

Navigare all’interno del filesystem 2/2

La struttura delle cartelle all’interno del fs è una struttura gerarchica per cui:

e di conseguenza:

Ad esempio, la cartella Documenti degli esempi precedenti è contenuta nella cartella andrea la quale è a sua volta contenuta nella cartella home. Infine, la cartella home è contenuta nella cartella principale del fs, la cartella / ( root ).

Per rappresentare questa situazione si utilizza la seguente scrittura sintetica: /home/andrea/Documenti

All’interno di ogni cartella (ad eccezione di / ) esiste una cartella speciale: ..

La cartella .. rappresenta un collegamento alla cartella di ordine superiore e permette di spostarsi su di essa.

andrea@ganimoide:~/Documenti$ cd ..
andrea@ganimoide:~$ pwd
/home/andrea

Copiare, rinominare, spostare e rimuovere file 1/2

Il comando cp copia file e cartelle in una cartella di destinazione:

andrea@ganimoide:~$ cp Documenti/relazione Documenti/relazioni/relazione

L’opzione -r copia ricorsivamente anche le sottocartelle contenute nella cartella di origine. In questo modo è possibile riprodurre nella cartella di destinazione l’intera struttura della cartella di partenza.

andrea@ganimoide:~$ cp -r Documenti/ backups/

Il comando mv ha una duplice funzione:

andrea@ganimoide:~$ mv Documenti/relazione Documenti/relazioni/
andrea@ganimoide:~$ mv Documenti/relazione Documenti/relazione_con_nuovo_nome

Esercizio

Utilizzando il terminale, consulta le pagine di manuale dei comandi cp e mv.

Copiare, rinominare, spostare e rimuovere file 2/2

Il comando rm permette di rimuovere file e cartelle.

andrea@ganimoide:~$ rm Documenti/relazione

L’opzione -r permette di rimuovere ricorsivamente anche le sottocartelle e il loro contenuto.

L’opzione -f (--force) disabilita la richiesta di conferma di eliminazione da parte dell’utente.

andrea@ganimoide:~$ rm -rf Documenti/relazioni

Il comando sopra rimuove la cartella relazioni e tutte le sottocartelle eventualmente contenute in essa.

Esercizio

Utilizzando il terminale, consulta le pagine di manuale del comando rm.

Cercare file: find

Per cercare file all’interno del fs la shell mette a disposizione il comando find.

Il comando find è in grado di effettuare ricerche di file seguendo svariati criteri.

Il caso più semplice consiste nel ricercare file in base al nome:

andrea@ganimoide:~$ find -name '*.png' 

L’esempio precedente ricerca ricorsivamente a partire dalla cartella in uso tutti i file con estensione png.

find può effettuare ricerche anche in base alla data di modifica dei file:

andrea@ganimoide:~$ find Documenti -mtime 0

L’esempio mostra come ricercare nella cartella Documenti tutti i file che sono stati modificati nelle ultime 24 ore.

find può eseguire dei comandi sui file identificati

andrea@ganimoide:~$ find -iname *.png -exec ls -l '{}' \;

Gestire file compressi 1/2

La shell offre un potente strumento di archiviazione e compressione: tar.

Il comando tar permette di archiviare in un unico file il contenuto di più file.

Il comando tar è in grado di utilizzare diversi algoritmi di compressione tra cui i più efficaci sono:

Per estrarre i file da un archivio compresso in formato gzip:

andrea@ganimoide:~$ tar xvzf archivio.tar.gz

Vediamo il significato delle opzioni:

Gestire file compressi 2/2

Per estrarre i file da un archivio compresso in formato bzip2:

andrea@ganimoide:~$ tar xvjf archivio.tar.bz2

Il significato delle opzioni è lo stesso dell’esempio precedente con la differenza dell’opzione j che indica il tipo di compressione bzip2.

Vediamo ora come creare un archivio compresso della cartella Documenti/ utilizzando i due algoritmi di compressione (gzip e bzip2).

andrea@ganimoide:~$ tar cvzf documenti.tar.gz Documenti/
andrea@ganimoide:~$ tar cvjf documenti.tar.bz2 Documenti/

Come si vede il comando tar necessita in questo caso di due argomenti: il nome del file di archivio e il nome della cartella da archiviare.

Si noti pure l’utilizzo dell’opzione c di creazione dell’archivio al posto dell’opzione di estrazione x.

I processi

I processi sono le attività in esecuzione in un sistema GNU/Linux.

Ad esempio, quando si invia un comando da shell, si attiva un processo che termina con la fine dell’esecuzione del comando.

I processi possono essere eseguiti in foreground o in background.

Il più delle volte i processi eseguiti in background sono applicazioni che non richiedono l’intervento dell’utente. Esse svolgono il proprio lavoro in modo silente, rimanendo “nascoste” all’utilizzatore.

Altre volte l’utente ha la necessità di lanciare un processo in background in modo da scorrelarne l’esecuzione dal terminale da cui è stato inviato il comando.

I processi eseguiti in foreground rimangono in uno stato di dipendenza dal terminale da cui sono stati eseguiti.

I processi: lanciare un comando in background

Per eseguire un processo in background si utilizza il simbolo & dopo il nome del comando:

andrea@ganimoide:~$ xman &
[1] 17308

Il valore tra parentesi quadre indica il numero progressivo di processi eseguiti dal terminale in uso. Il secondo valore è detto PID ed è un codice che identifica univocamente il processo lanciato.

Il PID di un processo è di fondamentale importanza poichè una volta lanciato il comando in background esso viene sganciato dalla shell in uso. Tramite il PID possiamo continuare a tracciare e a controllare l’esecuzione di un processo.

Ad esempio, per terminare l’esecuzione del processo appena lanciato ( xman ) si utilizza il comando kill seguito dal PID del processo:

andrea@ganimoide:~$ kill 17308
[1]+  Terminato               xman

I processi: ps 1/2

Per visualizzare le informazioni sui processi attualmente in esecuzione nel sistema la shell mette a disposizione il comando ps:

andrea@ganimoide:~$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   3056  1844 ?        Ss   Jan11   0:01 /sbin/init
root         2  0.0  0.0      0     0 ?        S<   Jan11   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S<   Jan11   0:00 [migration/0]
root         4  0.0  0.0      0     0 ?        S<   Jan11   0:16 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S<   Jan11   0:00 [watchdog/0]
root         9  0.0  0.0      0     0 ?        S<   Jan11   0:02 [events/0]
root        11  0.0  0.0      0     0 ?        S<   Jan11   0:00 [khelper]
andrea    5767  0.0  0.1  15064  2552 ?        S    22:29   0:00 /usr/bin/gnome...
andrea    5778  0.0  0.2  25272  6012 ?        Ssl  22:29   0:00 x-session-manager
...

L’esempio nel riquadro mostra un estratto dell’output del comando ps invocato con le seguenti opzioni:

I processi: ps 2/2

Vediamo il significato di alcune delle colonne nel riquadro di output dell’esempio precedente:

Variabili d’ambiente 1/3

Un altro importante caratteristica del sistema a cui avremo direttamente accesso da una shell Unix sono le VARIABILI D’AMBIENTE (ENVIRONMENT VARIABLES).

Le variabili d’ambiente sono delle variabili associate ad ogni processo sul sistema, le quali sono accessibili (indipendentemente dal linguaggio di programmazione utilizzato) attraverso un API di sistema e vengono tramandate di processo padre in processo figlio.

Attraverso la definizione di variabili d’ambiente è possibile manipolare alcuni comportamenti della shell e dei comandi di shell Unix.

Variabili d’ambiente 2/3

Per visualizzare le variabili d’ambiente definite nella shell in utilizzo è sufficiente eseguire il comando env :

$ env
SSH_AGENT_PID=2147
TERM=rxvt
SHELL=/bin/bash
DESKTOP_STARTUP_ID=awesome/rxvt/2293-12-ubik_TIME0
XDG_SESSION_COOKIE=fc45766d472a9ef3a469d82849f26d2e-1240842893.978998-96478676
WINDOWID=88080386
GTK_MODULES=canberra-gtk-module
USER=rpl
...

Variabili d’ambiente 3/3

Per visualizzare e settare una singola variabile d’ambiente si utilizzano i comandi echo ed export

$ echo $USER
rpl
$ export TERM=xterm

http://it.wikipedia.org/wiki/Variabile_d’ambiente_Unix

Elaborare flussi di dati

La shell mette a disposizione una serie di strumenti orientati alla manipolazione dei flussi di dati.

Un flusso di dati si può definire come una quantità di informazione che viene trasferita da un punto all’altro del sistema.

Consideriamo, ad esempio, le informazioni contenute all’interno di un file. Nel momento in cui visualizziamo sullo schermo queste informazioni, abbiamo stabilito un flusso di dati dal file verso lo schermo del terminale.

Un flusso di dati può attraversare il sistema anche dall’esterno verso l’interno. Ad esempio, quando l’utente digita un carattere sulla tastiera, stabilisce un flusso di dati che dalla periferica hardware raggiunge il sistema.

Anche due o più processi possono scambiare tra loro flussi di dati. Ad esempio, il flusso di dati generato dalla lettura di un file può confluire in un comando che lo filtra o lo modifica.

I flussi di dati percorrono il sistema e costituiscono la sua linfa vitale. Controllare la circolazione dei flussi di dati significa controllare totalmente le informazioni elaborate dal sistema.

Elaborare flussi di dati: standard I/O

Lo schermo del terminale è generalmente il punto di arrivo predefinito di ogni flusso di dati in uscita dall’elaboratore e diretto verso l’utente. Per questo motivo, esso viene definito standard output (stdout).

Allo stesso modo, il flusso di dati generato dalla tastiera dell’elaboratore e diretto verso il sistema è definito standard input (stdin).

Il binomio standard input/standard output si abbrevia in standard I/O.

Molti comandi della shell consentono di elaborare questi flussi di informazione in entrata e in uscita.

Ad esempio, il comando cat legge il contenuto di un file e visualizza il contenuto sullo stdout.

andrea@ganimoide:~$ cat /proc/meminfo 
MemTotal:      2041400 kB
MemFree:         88388 kB
Buffers:         40864 kB
...

Nel riquadro sopra si vede il risultato prodotto dal comando cat quando gli si passa come argomento il percorso di un file (/proc/meminfo) contenente le informazioni sulla memoria RAM del sistema.

Elaborare flussi di dati: ridirezionamento

La shell permette di direzionare i flussi di dati su file.

Come abbiamo visto, il comando cat produce un risultato sullo stdout (lo schermo del terminale). Nel riquadro sotto si vede come è possibile ridirezionare il risultato di cat in un file di nome meminfo.

andrea@ganimoide:~$ cat /proc/meminfo > meminfo

Questo tipo di sintassi consente di creare al volo file di testo:

andrea@ganimoide:~$ echo "Flusso di dati verso un file" > file_di_testo

Il comando echo invia sullo stdout la stringa passata come argomento. L’operatore > intercetta il flusso prodotto da echo e lo ridireziona verso un file di nome file_di_testo.

L’operatore >> svolge la stessa funzione di ridirezionamento dell’operatore > con la differenza che il flusso di dati viene accodato al contenuto del file.

andrea@ganimoide:~$ echo "In coda a file_di_testo" >> file_di_testo

Elaborare flussi di dati: pipes

Due o più comandi (processi) possono scambiarsi flussi di dati attraverso i pipes (tubi).

Si può pensare ai pipes come a dei raccordi di un sistema idraulico: essi regolano il flusso delle informazioni da un punto all’altro del sistema.

L’operatore pipe è denotato dal simbolo |.

In pratica, l’operatore | collega l’output di un comando con l’input di un altro.

andrea@ganimoide:~$ man ls | grep human
       -h, --human-readable
              with -l, print sizes in human readable format (e.g., 1K 234M 2G)

Nell’esempio riportato sopra, l’output del comando man viene fatto confluire nell’input del comando grep.

Il comando grep filtra le informazioni in ingresso alla ricerca della parola “human”.

Il risultato finale è l’estrapolazione di una parte del manuale di ls riguardante l’opzione --human-readable che consente di visualizzare le dimensioni dei file in un formato facilmente leggibile.

Processare flussi di dati: la sostituzione di comando

La shell offre la possibilità di utilizzare il risultato di un comando nell’invocazione di un altro. Questa operazione si dice sostituzione di comando.

Ad esempio, supponiamo di aver creato un file di nome da_rimuovere contenente un elenco di file da rimuovere.

Il comando che segue visualizza su stdout il contenuto del file.

andrea@ganimoide:~$ cat da_rimuovere
*~
*.tmp

Per effettuare l’operazione di eliminazione dei file in modo automatico possiamo utilizzare la sostituzione di comando:

andrea@ganimoide:~$ rm $(cat da_rimuovere)

In questo modo, l’output del comando cat (cioè l’elenco dei file da rimuovere) viene passato come input al comando rm che rimuove i file.

Processare flussi di dati: cut

Il comando cut permette di visualizzare sullo stdout parti del contenuto di un file.

Il comando cut risulta particolarmente utile per selezionare parti di file delimitate da particolari caratteri.

Nel riquadro sotto viene mostrato un esempio di utilizzo del comando cut. In particolare, interrogando il file /etc/passwd, si vuole ricavare l’elenco degli utenti accreditati nel sistema.

andrea@ganimoide:~$ cut -d: -f1 /etc/passwd
root
daemon
...

L’opzione -d consente di stabilire il carattere delimitatore in base al quale suddividere il contenuto del file in colonne.

L’opzione -f stabilisce quale colonna visualizzare.

L’argomento /etc/passwd corrisponde al nome del file da processare.

L’utilizzo del comando cut consente di estrapolare dalla grande quantità di informazioni contenute nel file /etc/passwd, solo i contenuti di interesse.

Processare flussi di dati: paste

Il comando paste permette di unire due o più flussi di dati in colonne verticali.

Supponiamo di poter visualizzare il contenuto di due file:

andrea@ganimoide:~$ cat file_1
A
B
C
andrea@ganimoide:~$ cat file_2
1
2
3

Il comando paste permette di fondere il contenuto di file_1 e file_2 separando ogni elemento con il carattere ‘:’

andrea@ganimoide:~$ paste -d':' file_1 file_2
A:1
B:2
C:3

Per esercizio, provate a ridirezionare l’output del comando precedente in un nuovo file.

Processare flussi di dati: tr

Il comando tr sostituisce o rimuove un particolare carattere (o una classe di caratteri) dal flusso di dati in ingresso.

Nell’esempio che segue si sostituiscono tutti i caratteri maiuscoli con i corrispondenti caratteri minuscoli:

andrea@ganimoide:~$ cat file_1 | tr A-Z a-z

Il comando tr può ricevere come argomento una classe di caratteri:

andrea@ganimoide:~$ cat file_1 | tr -d [:digit:]

Il comando precedente rimuove (opzione -d) dal flusso di dati in ingresso tutti i caratteri numerici. In questo caso la classe dei numeri è indicata dall’argomento [:digit:]

Infine, per rimuovere tutti gli spazi ripetuti (squeeze-repeats) all’interno di un flusso:

andrea@ganimoide:~$ cat file_1 | tr -s [:blank:]

Processare flussi di dati: sort

Il comando sort permette di ordinare i dati contenuti in un flusso.

Supponiamo di voler disporre in ordine alfabetico i nomi degli utenti del sistema. Ridirezionando l’output del comando cut attraverso l’operatore | possiamo scrivere:

andrea@ganimoide:~$ cut -d: -f1 /etc/passwd | sort
andrea
avahi
avahi-autoipd
...

Il comando sort può essere utile per ottenere rapidamente alcune statistiche relative all’utilizzo delle risorse di sistema:

andrea@ganimoide:~$ ps -eo pmem,cmd | sort -k 1 -n -r
33.7 /usr/lib/firefox-3.0.5/firefox
 5.2 /usr/X11R6/bin/X :0 -br -audit 0 -dpi 96 -auth /var/lib/gdm/:0.Xauth -nolisten tcp vt7
...

L’esempio sopra mostra la percentuale di memoria di sistema utilizzata da ogni singolo programma in esecuzione. I dati sono ordinati in modo decrescente (opzione -r).

Processare flussi di dati: tail e head

Un comando molto utile per la consultazione dei registri di sistema è tail.

Il comando tail visualizza sullo stdout le ultime linee di un file.

andrea@ganimoide:~$ tail /var/log/messages
Jan 18 16:33:36 ganimoide kernel: [148883.736086] usb 1-1: new low speed USB device...
...

L’esempio precedente mostra un utilizzo tipico del comando tail, cioè la lettura delle ultime linee del file /var/log/messages che registra molte importanti informazioni circa lo stato del sistema.

Un’opzione molto utile del comando tail è -f.

Quest’opzione consente di visualizzare in tempo reale i cambiamenti all’interno di un file permettendo all’utente di ottenere un feedback immediato sullo stato del sistema.

Al comando tail si contrappone il comando head che visualizza la parte iniziale di un file.

Processare flussi di dati: less e more

I comandi less e more permettono di impaginare flussi di dati che non possono essere visualizzati interamente sul terminale.

Ad esempio, se si provasse a visualizzare il contenuto del file /var/log/messages all’interno di un terminale di dimensioni standard, probabilmente non si riuscirebbe a contenere tutto il flusso di dati prodotto.

Il comando less produce una versione impaginata del contenuto del file.

andrea@ganimoide:~$ less /var/log/messages

Sfruttando l’operatore | il comando less è in grado di impaginare un flusso di dati qualsiasi.

andrea@ganimoide:~$ cat /var/log/messages | less

Lavorando su sistemi particolarmente limitati, il comando less potrebbe non essere disponibile. In tal caso, il comando more, seppur più primitivo, presenta le medesime funzionalità base di less.

Effettuare ricerche e sostituzioni

In un ambiente potente come la shell di sistema non possono mancare strumenti in grado di effettuare ricerche all’interno dei flussi di dati.

Ricercare all’interno di un flusso di dati ha un duplice scopo:

L’ambiente bash contiene numerosi strumenti per la ricerca e il filtraggio delle informazioni.

Molti di questi strumenti si basano sul concetto di espressioni regolari.

Le espressioni regolari sono dei particolari costrutti attraverso i quali è possibile descrivere i criteri di ricerca di determinati schemi ripetuti.

Nel seguito, dove necessario, utilizzeremo espressioni regolari molto semplici.

Alle espressioni regolari verra dedicata una lezione apposita.

Effettuare ricerche e sostituzioni: grep

Il comando grep consente di ricercare/filtrare informazioni all’interno di un flusso di dati.

andrea@ganimoide:~$ cat frutta.txt 
mele
pere
pompelmi
arance
andrea@ganimoide:~$ cat frutta.txt | grep pompelmi
pompelmi

L’esempio precedente mostra il risultato prodotto da grep nell’elaborare il flusso di dati alla ricerca della parola ‘pompelmi’.

L’esempio che segue mostra il filtraggio dell’output di ls alla ricerca di tutti i file con la prima lettera del nome maiuscola.

andrea@ganimoide:~$ ls | grep ^[A-Z]
Documenti
Examples
Immagini
Modelli

Effettuare ricerche e sostituzioni: sed

sed sta per stream editor ovvero un programma in grado di effettuare ricerche e sostituzioni all’interno di un flusso di dati.

sed è un software molto potente che offre svariate funzionalità.

Tuttavia, la funzione più utilizzata è quella di sostituzione.

andrea@ganimoide:~$ echo "prendere fischi per fiaschi" | sed 's/fischi/fiaschi/'
prendere fiaschi per fiaschi

Il comando echo nell’esempio sopra produce un flusso di dati che viene elaborato da sed.

L’elaborazione consiste nella ricerca della parola ‘fischi’ e nella sostituzione della stessa con la parola ‘fiaschi’.

Effettuare ricerche e sostituzioni: gawk 1/2

Oltre al comando sed, la shell mette a disposizione gawk un vero e proprio linguaggio di programmazione orientato all’elaborazione di file di testo (o flussi di dati).

La funzione basilare di gawk è quella di cercare degli schemi ripetuti (patterns) all’interno di flussi di dati. Quando uno schema viene identificato, gawk è in grado di eseguire una determinata azione programmata dall’utente.

La sintassi base di gawk è la seguente:

awk ‘pattern {action}’ input_file

dove pattern è in generale una espressione regolare.

Effettuare ricerche e sostituzioni: gawk 2/2

Una discussione approfondita su linguaggio gawk esula dagli obiettivi di questa lezione, tuttavia, si vogliono dare alcuni esempi di utilizzo di questo potente linguaggio.

andrea@ganimoide:~$ ls -l | awk '/Immagini/ { print }'
drwxr-xr-x  3 andrea andrea 4096 2009-01-16 12:51 Immagini

L’esempio precedente va interpretato in questo modo:

Esempi: Putting All Together

In questa slide vediamo alcuni esempi che combinano le conoscenze sulla linea di comando che abbiamo acquisito:

Crea un file contenente il nome degli utenti del sistema.

andrea@ganimoide:~$ awk -F":" '{ print $1 }' /etc/passwd > utenti

Visualizza la history della linea di comando e la impagina tramite less.

andrea@ganimoide:~$ history | less

Visualizza gli ultimi quattro comandi inviati:

andrea@ganimoide:~$ history | tail -4

Rimuove dalla cartella documenti tutti i file di backup:

andrea@ganimoide:~$ find -name '*~' | xargs rm 

Riepilogo

  • shell: bash, sh
  • documentazione: —help, man, info
  • processo: ps, top
  • variabili d’ambiente: env, echo, export
  • file, directory: pwd, cd, ls, mv, rm, cp
  • cercare file/comandi: which, find
  • archivi compressi: tar, gzip, bzip2
  • flussi I/O: cat, |, grep, $(), cut, paste, sort, tr, tail, head, sed, awk

Bibliografia

Libri Liberi

Copyright (C) 2009 - Alca Societa' Cooperativa

http://alcacoop.it - info@alcacoop.it

released under CreativeCommons 2.5 by-nc-sa