[inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]


61. Ricerche

Esistono due tipi di ricerche possibili: quelle all'interno dei file per identificare delle stringhe che corrispondono a un modello, e quelle fatte all'interno di un filesystem alla ricerca di file o directory in base alle loro caratteristiche (nome, date e altri attributi).

Per questo si utilizzano due programmi di utilità fondamentali: `grep' per le ricerche di stringhe e `find' per la ricerca dei file.

61.1 Grep GNU

Il programma Grep esegue una ricerca all'interno dei file in base a un modello espresso normalmente in forma di espressione regolare.

Storicamente sono esistite tre versioni di questo programma: `grep', `egrep' e `fgrep', ognuna specializzata in un tipo di ricerca. Attualmente, Grep GNU, corrispondente a quello che si utilizza normalmente con GNU/Linux, comprende tutte e tre queste funzionalità. In alcuni casi, per mantenere la compatibilità con il passato, possono trovarsi distribuzioni che mettono a disposizione anche i programmi `egrep' e `fgrep' in forma originale.

61.1.1 Avvio di grep

grep [<opzioni>] <modello> [<file>...]

grep [<opzioni>] -e <modello> [<file>...]

grep [<opzioni>] -f <file-modello> [<file>...]

`grep' esegue una ricerca all'interno dei file indicati come argomento oppure all'interno dello standard input. Il modello di ricerca può essere semplicemente il primo degli argomenti che seguono le opzioni, oppure può essere indicato precisamente come argomento dell'opzione `-e', oppure ancora può essere contenuto in un file che viene indicato attraverso l'opzione `-f'.

La tabella 61.1 elenca le opzioni principali.

Opzione Descrizione
-G Utilizza un'espressione regolare elementare (comportamento predefinito).
-E Utilizza un'espressione regolare estesa.
-F Utilizza un modello fatto di stringhe fisse.
-e <modello> Specifica il modello di ricerca.
-f <file> Specifica il nome di un file contenente il modello di ricerca.
-i Ignora la differenza tra maiuscole e minuscole.
-n Aggiunge il numero di riga.
-c Emette solo il totale delle righe corrispondenti per ogni file.
-h Elimina l'intestazione normale per le ricerche su più file.
-l Emette solo i nomi dei file per i quali la ricerca ha avuto successo.
-L Emette solo i nomi dei file per i quali la ricerca non ha avuto successo.
-v Inverte il senso della ricerca: valgono le righe che non corrispondono.

Tabella 61.1: Opzioni principali di `grep'.

61.1.2 Espressioni regolari

Un'espressione regolare è un modello che descrive un insieme di stringhe. Le espressioni regolari sono costruite, in maniera analoga alle espressioni matematiche, combinando espressioni più brevi.

Per tradizione esistono due tipi di espressioni regolari: elementari, o BRE, ed estese, o ERE (si vedano in particolare i capitoli dedicati alle espressioni regolari in generale: 182 e 183). Il programma `grep' originale era in grado di interpretare solo quelle elementari, Grep GNU interpreta correttamente anche quelle estese anche se il suo funzionamento predefinito è sempre basato su quelle elementari. Le espressioni regolari elementari sono limitate rispetto a quelle estese; in questo particolare adattamento di `grep' si ottengono le stesse funzionalità, pur se con una sintassi leggermente diversa da quella normale.

In generale, la sintassi delle espressioni regolari non è uguale per tutti i programmi che ne fanno uso, anche se esiste lo standard POSIX, che però è difficile trovare applicato in modo fedele.

Senza costringere il lettore a studiare subito i capitoli 182 e 183, dedicati alle espressioni regolari, viene data una descrizione sommaria delle espressioni regolari estese secondo GNU, e alla fine viene descritto come si comportano quelle elementari.

Il punto di partenza sono le espressioni regolari con le quali si ottiene una corrispondenza con un solo carattere. La maggior parte dei caratteri, includendo tutte le lettere e le cifre numeriche, sono espressioni regolari che corrispondono a loro stessi. Ogni metacarattere con significati speciali può essere utilizzato per il suo valore normale facendolo precedere dalla barra obliqua inversa (`\').

Una fila di caratteri racchiusa tra parentesi quadre corrisponde a un carattere qualunque tra quelli indicati; se all'inizio di questa fila c'è l'accento circonflesso, si ottiene una corrispondenza con un carattere qualunque diverso da quelli della fila. Per esempio, l'espressione regolare `[0123456789]' corrisponde a una qualunque cifra numerica, mentre `[^0123456789]' corrisponde a un carattere qualunque purché non sia una cifra numerica.

All'interno delle parentesi quadre, invece che indicare un insieme di caratteri, è possibile indicarne un intervallo, mettendo il carattere iniziale e finale separati da un trattino (`-'). I caratteri che vengono rappresentati in questo modo dipendono dalla codifica che ne determina la sequenza. Per esempio, in base alla codifica ASCII, l'espressione regolare `[9-A]' rappresenta un carattere qualsiasi tra: `9', `:', `;', `<', `=', `>', `?', `@' e `A'.

All'interno delle parentesi quadre si possono indicare delle classi di caratteri attraverso il loro nome: `[:alnum:]', `[:alpha:]', `[:cntrl:]', `[:digit:]', `[:graph:]', `[:lower:]', `[:print:]', `[:punct:]', `[:space:]', `[:upper:]' e `[:xdigit:]'. Per essere usati, questi nomi di classi possono solo apparire all'interno di un'espressione tra parentesi quadre, di conseguenza, per esprimere la corrispondenza con un qualunque carattere alfanumerico si può utilizzare l'espressione regolare `[[:alnum:]]'. Nello stesso modo, per esprimere la corrispondenza con un qualunque carattere non alfanumerico si può utilizzare l'espressione regolare `[^[:alnum:]]'.

Il punto (`.') corrisponde a un qualsiasi carattere. Il simbolo `\w' è un sinonimo di `[[:alnum:]]' e `\W' è un sinonimo di `[^[:alnum:]]'.

L'accento circonflesso (`^') e il dollaro (`$') sono metacaratteri che corrispondono rispettivamente alla stringa nulla all'inizio e alla fine di una riga. I simboli `\<' e `\>' corrispondono rispettivamente alla stringa vuota all'inizio e alla fine di una parola.

Quando per qualche ragione si hanno difficoltà a indicare dei caratteri che per l'espressione sarebbero comunque caratteri normali, è possibile utilizzare il simbolo `\' anteriormente, purché questo non rappresenti a sua volta un altro metacarattere.

Un'espressione regolare che genera una corrispondenza con un carattere singolo, può essere seguita da uno o più operatori di ripetizione. Questi sono rappresentati attraverso i simboli `?', `*', `+' e dai «contenitori» rappresentati da particolari espressioni tra parentesi graffe. La tabella 61.2 mostra l'uso che si può fare di questi operatori.

Codifica Corrispondenza.
x* Nessuna o più volte x. Equivalente a `x{0,}'.
x? Nessuna o al massimo una volta x. Equivalente a `x{0,1}'.
x+ Una o più volte x. Equivalente a `x{1,}'.
x{n} Esattamente n volte x.
x{n,} Almeno n volte x.
x{n,m} Da n a m volte x.

Tabella 61.2: Operatori di ripetizione nelle espressioni regolari estese gestite da Grep GNU.

Due espressioni regolari possono essere concatenate (in sequenza) generando un'espressione regolare corrispondente alla sequenza di due sottostringhe che rispettivamente corrispondono alle due sottoespressioni.

Due espressioni regolari possono essere unite attraverso l'operatore `|'; l'espressione regolare risultante corrisponde a una qualunque stringa per la quale sia valida la corrispondenza di una delle due sottoespressioni.

La ripetizione (attraverso gli operatori di ripetizione) ha la precedenza sul concatenamento che a sua volta ha la precedenza sull'alternanza (quella che si ha utilizzando l'operatore `|'). Una sottoespressione può essere racchiusa tra parentesi tonde per modificare queste regole di precedenza.

La notazione `\n', dove n è una singola cifra numerica diversa da zero, rappresenta un riferimento all'indietro a una corrispondenza già avvenuta tra quelle di una sottoespressione precedente racchiusa tra parentesi tonde. La cifra numerica indica l'n-esima sottoespressione tra parentesi a partire da sinistra.

Nelle espressioni regolari elementari, i metacaratteri `?', `+', `{', `|', `(' e `)' perdono il loro significato speciale. Al loro posto si possono utilizzare gli stessi simboli preceduti dalla barra obliqua inversa: `\?', `\+', `\{', `\|', `\(' e `\)'. *1*

61.1.3 egrep

Come già accennato, alcune distribuzioni GNU/Linux forniscono un programma `egrep' alternativo, invece di utilizzare il solito collegamento allo stesso `grep'. In tal caso, per quanto riguarda l'interpretazione delle espressioni regolari (estese), la parentesi graffa aperta che inizia la delimitazione di un «contenitore» per rappresentare un operatore di ripetizione, viene indicata come `\{'.

61.1.4 Esempi

grep -F -e ciao -i -n *

Cerca all'interno di tutti i file contenuti nella directory corrente la corrispondenza della parola `ciao' senza considerare la differenza tra le lettere maiuscole e quelle minuscole. Visualizza il numero e il contenuto delle righe che contengono la parola cercata.

grep -E -e "scal[oa]" elenco

Cerca all'interno del file `elenco' le righe contenenti la parola `scalo' o `scala'.

grep -E -e \`.*\' elenco

Questo è un caso di ricerca particolare in cui si vogliono cercare le righe in cui appare qualcosa racchiuso tra apici singoli, nel modo ``...''. Si immagina però di utilizzare la shell Bash con la quale è necessario proteggere gli apici da un altro tipo di interpretazione. In questo caso la shell fornisce a `grep' solo la stringa ``.*''.

grep -E -e "\`.*\'" elenco

Questo esempio deriva dal precedente. Anche in questo caso si suppone di utilizzare la shell Bash, ma questa volta viene fornita a `grep' la stringa ``.*\'' che fortunatamente viene interpretata ugualmente da `grep' nel modo corretto.

61.1.5 zgrep

zgrep [<opzioni>] <modello> [<file>...]

`zgrep' è un programma aggiuntivo che permette di eseguire delle ricerche all'interno di file compressi (con `compress', oppure con `gzip'). `zgrep' si occupa semplicemente di decomprimere i file, se necessario, prima di passarli a `grep'. In questo senso, e considerato che le opzioni e il modello sono passati tali e quali a `grep', la sintassi è la stessa di quel programma.

Ricapitolando, `zgrep' può essere usato indifferentemente con file normali o compressi, senza che l'utente debba preoccuparsi di questo.

61.2 find

Il programma `find' esegue una ricerca, all'interno di uno o più percorsi, per i file che soddisfano delle condizioni determinate, legate alla loro apparenza esterna e non al loro contenuto. Per ogni file o directory trovati, può essere eseguito un comando (programma, script o altro) che a sua volta può svolgere delle operazioni su di essi.

Questa sezione non descrive tutte le funzionalità di `find'. Una volta appresi i rudimenti del suo funzionamento, conviene consultare find.info oppure find(1).

61.2.1 Avvio di find

La sintassi di `find' è piuttosto insolita, oltre che complessa, anche se dallo schema seguente non sembrerebbe così.

In particolare è indispensabile tenere a mente che molti dei simboli utilizzati negli argomenti di `find' potrebbero essere interpretati e trasformati dalla shell, di conseguenza occorrerà utilizzare le tecniche che la shell stessa offre per evitarlo.

find [<percorso>...] [<espressione>]

`find' esegue una ricerca all'interno dei percorsi indicati per i file che soddisfano l'espressione di ricerca. Il primo argomento che inizia con `-', `(', `)', `,' o `!' (trattino, parentesi tonda, virgola, punto esclamativo) viene considerato come l'inizio dell'espressione, mentre gli argomenti precedenti sono interpretati come parte dell'insieme dei percorsi di ricerca.

Se non vengono specificati percorsi di ricerca, si intende la directory corrente; se non viene specificata alcuna espressione, o semplicemente se non viene specificato nulla in contrario, viene emesso l'elenco dei nomi trovati.

61.2.2 Espressioni di find

Il concetto di espressione nella documentazione di `find' è piuttosto ampio e bisogna fare un po' di attenzione. Si può scomporre idealmente in

[<opzione>...] [<condizioni>]

e a sua volta le condizioni possono essere di due tipi: test e azioni. Ma, mentre le opzioni devono apparire prima, test e azioni possono essere mescolati tra loro.

Le opzioni rappresentano un modo di configurare il funzionamento del programma, così come di solito accade nei programmi di utilità. Le condizioni sono espressioni che generano un risultato logico e come tali vanno trattate: per concatenare insieme più condizioni occorre utilizzare gli operatori booleani.

61.2.3 Alcune opzioni

Come già accennato, dopo l'indicazione dei percorsi e prima delle condizioni (test e azioni) vanno indicate le opzioni. Quelle che seguono sono solo le più importanti tra quelle a disposizione.

---------

-depth

Elabora prima il contenuto delle directory. In pratica si ottiene una scansione che parte dal livello più profondo fino al più esterno.

-xdev | -mount

Non esegue la ricerca nelle directory contenute all'interno di filesystem differenti da quello di partenza. Tra i due è preferibile usare `-xdev'.

-noleaf

Non ottimizza la ricerca. Questa opzione è necessaria quando si effettuano ricerche all'interno di filesystem che non seguono le convenzioni Unix, come nel caso di CD-ROM senza le estensioni necessario, o partizioni Dos.

Esempi

find . -xdev -print

Elenca tutti i file e le directory a partire dalla posizione corrente restando nell'ambito del filesystem di partenza.

61.2.4 Alcuni test

Come già accennato, i test sono condizioni che vengono valutate per ogni file e directory incontrati. Il risultato delle condizioni può essere Vero o Falso. Quando vengono indicate più condizioni, queste devono essere unite in qualche modo attraverso degli operatori booleani in modo da ottenere una sola grande condizione. Se non viene specificato diversamente, viene utilizzato automaticamente l'operatore AND: `-and'.

Valori numerici

All'interno dei test, gli argomenti numerici possono essere specificati preceduti o meno da un segno.

---------

+n

Indica un numero maggiore di n.

-n

Indica un numero minore di n.

n

Indica un numero esattamente uguale a n.

Proprietà

-uid n

Si avvera quando il numero UID del file o della directory è uguale a n.

-user <nome-dell'utente>

Si avvera quando il file o la directory appartiene all'utente indicato.

-nouser

Si avvera per i file e le directory di proprietà di utenti non esistenti.

-gid n

Si avvera quando il numero GID del file o della directory è uguale a n.

-group <nome-del-gruppo>

Si avvera quando il file o la directory appartiene al gruppo indicato.

-nogroup

Si avvera per i file e le directory di proprietà di gruppi non esistenti.

Permessi

-perm <permessi>

Si avvera quando i permessi del file o della directory corrispondono esattamente a quelli indicati con questo test. I permessi si possono indicare in modo numerico (ottale) o simbolico.

-perm -<permessi>

Si avvera quando i permessi del file o della directory comprendono almeno quelli indicati con questo test.

-perm +<permessi>

Si avvera quando alcuni dei permessi indicati nel modello di questo test corrispondono a quelli del file o della directory.

Caratteristiche dei nomi

-name <modello>

Si avvera quando viene incontrato un nome di file o directory corrispondente al modello indicato, all'interno del quale si possono utilizzare i caratteri jolly. La comparazione avviene utilizzando solo il nome del file (o della directory) escludendo il percorso precedente. I caratteri jolly (`*', `?', `[', `]') non possono corrispondere al punto iniziale (`.') che appare nei cosiddetti file nascosti.

-iname <modello>

Si comporta come `-name', ma non tiene conto della differenza tra maiuscole e minuscole (`iname' = insensitive `name').

-lname <modello>

Si avvera quando si tratta di un collegamento simbolico e il suo contenuto corrisponde al modello che può essere espresso utilizzando anche i caratteri jolly. Un collegamento simbolico può contenere anche l'indicazione del percorso necessario a raggiungere un file o una directory reale. Il modello espresso attraverso i caratteri jolly non tiene conto in modo particolare dei simboli punto (`.') e barra obliqua (`/') che possono essere contenuti all'interno del collegamento.

-ilname <modello>

Si comporta come `-lname', ma non tiene conto della differenza tra maiuscole e minuscole (`ilname' = insensitive `lname').

-path <modello>

Si avvera quando il modello, esprimibile utilizzando caratteri jolly, corrisponde a un percorso. Per esempio, un modello del tipo `./i*no' può corrispondere al file `./idrogeno/ossigeno'.

-ipath <modello>

Si comporta come `-path', ma non tiene conto della differenza tra maiuscole e minuscole (`ipath' = insensitive `path').

-regexp <modello>

Si avvera quando l'espressione regolare indicata corrisponde al file o alla directory incontrati. Per la verifica della corrispondenza, attraverso l'espressione regolare, viene utilizzato anche il percorso e non solo il nome del file o della directory. Quindi, per ottenere la corrispondenza con il file `./carbonio' si può utilizzare l'espressione regolare `.*bonio' oppure `.*bo..o', ma non `c.*io'.

-iregexp <modello>

Si comporta come `-regexp', ma non tiene conto della differenza tra maiuscole e minuscole (`iregexp' = insensitive `regexp').

Data di modifica

-mmin n

Si avvera quando la data di modifica del file o della directory corrisponde a n minuti fa.

-mtime n

Si avvera quando la data di modifica del file o della directory corrisponde a n giorni fa. Più precisamente, il valore n fa riferimento a multipli di 24 ore.

-newer <file>

Si avvera quando la data di modifica del file o della directory è più recente di quella del file indicato.

Data di accesso

-amin n

Si avvera quando la data di accesso del file o della directory corrisponde a n minuti fa.

-atime n

Si avvera quando la data di accesso del file o della directory corrisponde a n giorni fa. Più precisamente, il valore n fa riferimento a multipli di 24 ore.

-anewer <file>

Si avvera quando la data di accesso del file o della directory è più recente di quella del file indicato.

Data di creazione o cambiamento di stato

-cmin n

Si avvera quando la data di creazione del file o della directory corrisponde a n minuti fa.

-ctime n

Si avvera quando la data di creazione del file o della directory corrisponde a n giorni fa. Più precisamente, il valore n fa riferimento a multipli di 24 ore.

-cnewer <file>

Si avvera quando la data di creazione del file o della directory è più recente di quella del file indicato.

Dimensione

-empty

Si avvera quando il file o la directory sono vuoti.

-size n[b|c|k|w]

Si avvera quando la dimensione del file o della directory ha una dimensione pari a n. L'unità di misura è rappresentata dalla lettera che segue il numero:

  • `b'   blocchi da 512 byte e rappresenta il valore predefinito in mancanza dell'indicazione di questa lettera;

  • `c'   byte (caratteri);

  • `k'   blocchi da 1024 byte (Kbyte);

  • `w'   parole di 2 byte.

Varie

-true

Sempre vero.

-false

Sempre falso.

-fstype <tipo-di-filesystem>

Si avvera quando il file o la directory si trova in un filesystem del tipo indicato (Vedere tabella 52.2).

-inum n

Si avvera quando il file o la directory ha il numero di inode corrispondente a n.

-type <categoria>

Si avvera se l'elemento analizzato appartiene alla categoria indicata:

  • `b'   dispositivo a blocchi;

  • `c'   dispositivo a caratteri;

  • `d'   directory;

  • `p'   file FIFO, ovvero una pipe con nome;

  • `f'   file normale (regular file);

  • `l'   collegamento simbolico;

  • `s'   socket.

61.2.5 Operatori booleani

Le condizioni possono essere costruite anche utilizzando alcuni operatori booleani e le parentesi. Quando questi vengono utilizzati, la valutazione delle condizione viene fatta eseguendo il minimo numero indispensabile di operazioni. Ciò significa che di fronte a un operatore AND si verifica la prima condizione e solo se questa risulta vera si passa a verificare la seconda; di fronte a un operatore OR si verifica la prima condizione e solo se questa risulta falsa si passa a verificare la seconda. Infatti, per sapere che il risultato di un'operazione AND è Falso basta sapere che almeno una delle due condizioni in ingresso ha un valore Falso; per sapere che il risultato di un'operazione OR è Vero basta sapere che almeno una delle due condizioni in ingresso ha il valore Vero.

---------

(   )

Le parentesi tonde stabiliscono la precedenza nell'esecuzione dei test.

! | -not

Davanti a un'espressione si comporta come negazione logica, ovvero è equivalente a NOT.

-a | -and

Tra due espressioni si comporta come l'operatore logico AND. In mancanza dell'indicazione di un operatore logico tra due condizioni si intende AND.

-o | -or

Tra due espressioni si comporta come l'operatore logico OR.

61.2.6 Alcune azioni

Le azioni sono delle operazioni da compiere per ogni file o directory che si ottiene dalla scansione. Queste azioni generano però un risultato che viene interpretato in maniera logica. Dipende da come vengono concatenate le varie condizioni (test e azioni) se, e in corrispondenza di quanti file, verranno eseguite queste azioni.

-exec <comando> ; 

Esegue il comando indicato, nella directory di partenza, restituendo il valore Vero se il comando restituisce il valore zero. Tutti gli argomenti che seguono vengono considerati come parte del comando fino a quando viene incontrato il simbolo punto e virgola (`;'). All'interno del comando, la stringa `{}' viene interpretata come sinonimo del file che è attualmente in corso di elaborazione. Se la shell interpreta questo simbolo occorre utilizzare il meccanismo della protezione per evitarlo.

-ok <comando> ; 

Si comporta come `-exec' ma, prima di eseguire il comando, chiede conferma all'utente. Se il comando non viene eseguito, restituisce il valore Falso.

-print

Si avvera sempre, emette il nome completo dei file (e delle directory) che avverano l'insieme delle condizioni. È l'azione predefinita, se non ne vengono indicate delle altre. *2*

61.2.7 Esempi

find / -name "lib*" -print

Esegue una ricerca su tutto il filesystem globale, a partire dalla directory radice, per i file e le directory il cui nome inizia per `lib'. Dal momento che si vuole evitare che la shell trasformi `lib*' in qualcosa di diverso, si utilizzano le virgolette.

find / -xdev -nouser -print

Esegue una ricerca nel filesystem principale a partire dalla directory radice, escludendo gli altri filesystem, per i file e le directory appartenenti a utenti non registrati (che non risultano da `/etc/passwd').

find /usr -xdev -atime +90 -print

Esegue una ricerca a partire dalla directory `/usr/', escludendo altri filesystem diversi da quello di partenza, per i file la cui data di accesso è più vecchia di 2160 ore (24*90=2160).

find / -xdev -type f -name core -print

Esegue una ricerca a partire dalla directory radice, all'interno del solo filesystem principale, per i file `core' (solo i file normali).

find / -xdev -size +5000k -print

Esegue una ricerca a partire dalla directory radice, all'interno del solo filesystem principale, per i file la cui dimensione supera i 5000 Kbyte.

find ~/dati -atime +90 -exec mv \{\} ~/archivio \;

Esegue una ricerca a partire dalla directory `~/dati/' per i file la cui data di accesso è più vecchia di 90 giorni, e sposta quei file all'interno della directory `~/archivio/'. Il tipo di shell a disposizione ha costretto a usare spesso il carattere di escape (`\') per poter usare le parentesi graffe e il punto e virgola secondo il significato che gli attribuisce `find', e non la shell stessa.

---------------------------

Appunti Linux 2000.04.12 --- Copyright © 1997-2000 Daniele Giacomini --  daniele @ pluto.linux.it


1.) La descrizione fatta delle espressioni regolari estese di Grep GNU è incompleta. Per i dettagli che mancano conviene consultare i capitoli che trattano in maniera specifica questo argomento, che sono già stati indicati in precedenza.

2.) Il programma `find' di GNU considera questa l'azione predefinita, per cui non è necessario indicarla per ottenere un output sullo schermo. Generalmente, `find' non ha un'azione predefinita, e questo può mettere in crisi un utente GNU/Linux quando passa a un altro sistema Unix. Questo è il motivo per il quale viene sempre indicata l'azione negli esempi seguenti, anche se non sarebbe necessario.


[inizio] [indice generale] [precedente] [successivo] [indice analitico] [contributi]