GNU/Linux: manipolare il testo con sed

sed è uno di quei comandi che si usano tutti i giorni senza accorgersene: serve principalmente a sostituire e manipolare il contenuto di file o, più in generale, di stringhe. In questo articolo vediamo la logica di base e gli usi più comuni, senza addentrarci nei casi più tecnici.

La sintassi

sed vuole due argomenti: il primo è lo script da eseguire (la sostituzione, o qualunque altra cosa vogliamo fare), il secondo è il file su cui lavorare. In alternativa può leggere dallo standard input e scrivere sullo standard output, quindi si concatena con pipe e redirezioni come gli altri comandi.

La sostituzione

Il primo esempio è il più semplice: sostituiamo la parola mondo con la parola Mario in una stringa passata in pipe. Lo script di sostituzione comincia con s, e usa lo slash come separatore: s, separatore, cosa cercare, separatore, con cosa sostituirlo, separatore.

echo "ciao mondo" | sed 's/mondo/Mario/'

Lo stesso esempio con un file. Scriviamo una stringa in mondo.txt e passiamo il file a sed:

echo "ciao mondo" > mondo.txt
sed 's/mondo/Mario/' mondo.txt

sed legge il contenuto del file, applica la sostituzione e scrive il risultato sullo standard output. Il file non viene toccato: se vogliamo salvare il risultato dobbiamo usare la redirezione dell’output (oppure l’opzione -i, che modifica il file sul posto, ma è un’altra storia).

Le occorrenze multiple

Aggiungiamo un paio di righe al file, in modo che la parola compaia più volte:

printf 'ciao mondo, mondo e mondo\nmondo mondo\n' > mondo.txt
printf 'mondo e ancora mondo\n' >> mondo.txt
cat mondo.txt

Se lanciamo di nuovo la sostituzione, vediamo che viene sostituita solo la prima occorrenza. Attenzione: la sostituzione si applica per riga, quindi senza altre indicazioni viene sostituita la prima occorrenza di ogni riga.

sed 's/mondo/Mario/' mondo.txt

Se mettiamo un numero in fondo, sed sostituisce l’occorrenza indicata, sempre per ogni riga. Qui la seconda:

sed 's/mondo/Mario/2' mondo.txt

E qui la terza. Se in una riga non c’è una terza occorrenza, quella riga resta com’è:

sed 's/mondo/Mario/3' mondo.txt

Per sostituire tutte le occorrenze si usa il flag g, che sta per global:

sed 's/mondo/Mario/g' mondo.txt

I due flag si combinano: un numero seguito da g significa “dalla N-esima occorrenza in avanti”. Per esempio, dalla seconda in poi:

sed 's/mondo/Mario/2g' mondo.txt

Scegliere le righe

Possiamo limitare la sostituzione a una riga specifica mettendo il numero di riga davanti allo script. Qui solo la seconda riga (e solo la prima occorrenza):

sed '2s/mondo/Mario/' mondo.txt

Le due cose si combinano: seconda riga, seconda occorrenza:

sed '2s/mondo/Mario/2' mondo.txt

Prima riga, tutte le occorrenze:

sed '1s/mondo/Mario/g' mondo.txt

Funzionano anche gli intervalli. Per sostituire solo nelle prime due righe:

sed '1,2s/mondo/Mario/' mondo.txt

Il flag p E l’opzione -N

Aggiungiamo altre due righe al file, una delle quali senza la parola mondo, e introduciamo il flag p:

printf 'una riga con la parola\n' >> mondo.txt
printf 'nessuna sostituzione qui\n' >> mondo.txt
cat mondo.txt

Il flag p fa una cosa che sembra strana: stampa una seconda volta le righe in cui è avvenuta una sostituzione. Le righe dove non è stata fatta nessuna sostituzione compaiono una volta sola.

sed 's/mondo/Mario/p' mondo.txt

Questo comportamento diventa utilissimo insieme all’opzione -n, che sopprime la stampa automatica: restano visibili solo le righe stampate esplicitamente, cioè quelle dove la sostituzione è avvenuta.

sed -n 's/mondo/Mario/p' mondo.txt

Naturalmente si combina con gli altri flag. Qui vediamo soltanto le righe che contenevano la parola mondo almeno tre volte, con le occorrenze dalla terza in poi sostituite:

sed -n 's/mondo/Mario/3gp' mondo.txt

Cancellare righe

Il comando d cancella righe dall’output. Il file non cambia, sono le righe a non essere stampate. Per eliminare la terza riga:

sed '3d' mondo.txt

Il simbolo del dollaro indica sempre l’ultima riga, anche se non sappiamo quante righe abbia il file. Per eliminare l’ultima:

sed '$d' mondo.txt

Il dollaro si può usare anche negli intervalli. Per eliminare dalla terza riga fino alla fine, in modo da vedere solo le prime due:

sed '3,$d' mondo.txt

d funziona anche con il pattern matching: per eliminare tutte le righe che contengono una certa parola.

sed '/mondo/d' mondo.txt

Oppure, al contrario, per eliminare quelle che contengono la parola parola:

sed '/parola/d' mondo.txt

Stampare solo certe righe

Il discorso funziona anche al contrario: con il comando p possiamo chiedere a sed di stampare un certo intervallo di righe. Senza -n le righe selezionate vengono stampate due volte, con -n le vediamo solo una volta:

sed '1,3p' mondo.txt
sed -n '1,3p' mondo.txt

Aggiungere righe

Con il comando a (append) si aggiunge una riga dopo quelle che corrispondono al pattern. Qui inseriamo una riga di esempio dopo ogni riga che contiene la parola parola:

sed '/parola/a riga di esempio' mondo.txt

Se invece la nuova riga deve andare prima di quella che corrisponde, si usa il comando i (insert):

sed '/parola/i riga di esempio' mondo.txt

Per finire

sed supporta una quantità enorme di opzioni e di comportamenti, anche molto complessi. Qui ho voluto presentarlo e mostrare gli usi più comuni: sostituire, selezionare, cancellare, stampare e aggiungere righe. Il consiglio è sempre lo stesso: aprite la vostra Linux box e giocateci, finché non vi diventa naturale. Se volete un approfondimento sui casi più complessi, fatemelo sapere.

Link e risorse

Sostieni il canale

PER SOSTENERE IL CANALE BASTANO UN LIKE E UN’ISCRIZIONE!

questi link sono affiliati Amazon, acquistando i libri che ti consiglio sostieni il canale!