Salta al contenuto principale

sed (stream editor)

Inviato da tuxsa il

sed (stream editor) è un editor di testo non interattivo: legge un flusso di testo (un file o l'output di un altro comando), applica le trasformazioni richieste e scrive il risultato sullo standard output. Nasce nel 1974 ai Bell Labs, è definito dallo standard POSIX e su Linux si usa di norma l'implementazione GNU sed, che aggiunge alcune estensioni utili.

Il suo punto di forza è lavorare riga per riga, senza caricare l'intero file in memoria. Per questo funziona bene anche su file enormi o in pipeline come journalctl | sed ....

Come funziona

Per ogni riga in input, sed esegue questo ciclo:

  1. legge la riga e la copia nel pattern space, un buffer di lavoro;
  2. esegue sul pattern space tutti i comandi dello script, in ordine;
  3. stampa il pattern space (a meno che non si usi -n);
  4. passa alla riga successiva.

Esiste anche un secondo buffer, l'hold space, che sopravvive tra un ciclo e l'altro e permette operazioni più avanzate.

Sintassi di base

sed [OPZIONI] 'SCRIPT' [FILE...]
comando | sed [OPZIONI] 'SCRIPT'

Ogni istruzione ha la forma [indirizzo]comando. Senza indirizzo, il comando vale per tutte le righe.

Opzioni principali

OpzioneSignificato
-nnon stampa automaticamente il pattern space (si stampa solo con p)
-e SCRIPTaggiunge uno script; si può ripetere più volte
-f FILElegge lo script da un file
-i[SUFFISSO]modifica il file sul posto; con suffisso crea un backup
-E (o -r)usa le espressioni regolari estese (ERE)
-stratta ogni file come flusso separato (utile con $ e numeri di riga)
-zusa il carattere nullo come separatore di riga invece del newline

Indirizzi

IndirizzoSignificato
5riga 5
$ultima riga
3,8righe da 3 a 8
/regex/righe che corrispondono alla regex
/ini/,/fine/dalla prima riga che contiene "ini" fino alla prima che contiene "fine"
1~2una riga ogni due, a partire dalla prima (GNU)
5,+3riga 5 e le 3 successive (GNU)
indirizzo!nega la selezione

Comandi più usati

ComandoAzione
s/re/sost/flagsostituzione
dcancella il pattern space e passa alla riga successiva
pstampa il pattern space
i\testoinserisce testo prima della riga
a\testoaggiunge testo dopo la riga
c\testosostituisce l'intera riga con il testo
y/abc/xyz/traslittera i caratteri (come tr)
=stampa il numero di riga
qesce subito
n / Nlegge la riga successiva (sostituendo / accodando al pattern space)
h H g G xcopiano, accodano e scambiano tra pattern space e hold space

Il comando s in dettaglio

È di gran lunga il comando più usato:

s/espressione/sostituzione/flag

I flag più comuni sono:

  • g: sostituisce tutte le occorrenze nella riga (senza, solo la prima);
  • N: sostituisce solo l'N-esima occorrenza;
  • i o I: ignora maiuscole e minuscole (GNU);
  • p: stampa la riga se è avvenuta una sostituzione (si combina con -n);
  • w file: scrive su file le righe modificate.

Nella sostituzione, & rappresenta tutto il testo che ha fatto match, e \1, \2… i gruppi catturati. Il delimitatore non deve per forza essere /: con i percorsi conviene usare | o #.

Esempi pratici

1. Sostituzioni semplici

# prima occorrenza per riga
sed 's/gatto/cane/' file.txt

# tutte le occorrenze
sed 's/gatto/cane/g' file.txt

# solo la seconda occorrenza per riga
sed 's/gatto/cane/2' file.txt

# ignora maiuscole/minuscole
sed 's/gatto/cane/gI' file.txt

# delimitatore alternativo, comodo con i percorsi
sed 's|/var/www|/srv/www|g' config.conf

2. Stampare e cancellare righe

# stampa solo le righe 10-20
sed -n '10,20p' file.txt

# stampa solo la riga 5
sed -n '5p' file.txt

# cancella la prima riga (utile per togliere un'intestazione)
sed '1d' file.csv

# cancella l'ultima riga
sed '$d' file.txt

# cancella le righe pari
sed '2~2d' file.txt

# conta le righe (come wc -l)
sed -n '$=' file.txt

3. Ripulire un file di configurazione

# rimuove commenti e righe vuote
sed '/^#/d;/^$/d' /etc/ssh/sshd_config

# rimuove anche i commenti a fine riga e gli spazi superflui
sed -E 's/[[:space:]]*#.*$//;/^[[:space:]]*$/d' file.conf

4. Modificare un file sul posto

# crea un backup file.conf.bak e poi modifica
sed -i.bak 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config

Con -i senza suffisso non resta alcun backup. Il consiglio è di provare prima senza -i e controllare l'output.

5. Inserire, aggiungere e cambiare righe

# inserisce una riga prima della riga 3
sed '3i\# Configurazione rivista' file.conf

# aggiunge una riga dopo ogni riga che contiene "[main]"
sed '/\[main\]/a\debug = false' file.conf

# sostituisce l'intera riga che inizia con "port="
sed '/^port=/c\port=8080' file.conf

6. Espressioni regolari estese e gruppi

# converte le date da gg/mm/aaaa ad aaaa-mm-gg
echo "01/10/2026" | sed -E 's|([0-9]{2})/([0-9]{2})/([0-9]{4})|\3-\2-\1|'
# 2026-10-01

# racchiude ogni numero tra parentesi quadre usando &
echo "ordine 42 e 7" | sed -E 's/[0-9]+/[&]/g'
# ordine [42] e [7]

# toglie spazi iniziali e finali
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' file.txt

7. Lavorare su intervalli di righe

# stampa solo il blocco tra due marcatori
sed -n '/BEGIN/,/END/p' file.txt

# sostituisce solo all'interno del blocco
sed '/<pre>/,/<\/pre>/s/foo/bar/g' pagina.html

# applica più comandi a un indirizzo con le graffe
sed -n '/ERROR/{=;p}' app.log

8. Uso in pipeline

# estrae gli indirizzi IP da una riga di log
echo 'Failed password from 203.0.113.7 port 22' \
  | sed -E 's/.*from ([0-9.]+) port.*/\1/'

# sostituisce un dominio in un dump SQL
sed 's/vecchio-dominio\.it/nuovo-dominio.it/g' dump.sql > dump-nuovo.sql

Attenzione al secondo esempio: se il dump contiene dati PHP serializzati (cosa comune in Drupal e WordPress), cambiare la lunghezza delle stringhe con sed li corrompe, perché la lunghezza è scritta nel dato stesso. In quei casi servono strumenti che ne tengono conto, come wp search-replace per WordPress; su Drupal conviene intervenire dall'applicazione (per esempio con drush e le API dei contenuti) invece di modificare il dump a mano.

9. Un assaggio di hold space

# inverte l'ordine delle righe (equivalente di tac)
sed '1!G;h;$!d' file.txt

# comprime più righe vuote consecutive in una sola
sed '/^$/N;/\n$/D' file.txt

# unisce tutte le righe in una sola, separate da virgola
sed ':a;N;$!ba;s/\n/,/g' file.txt

Il terzo è un piccolo ciclo: :a definisce un'etichetta, N accoda la riga successiva e $!ba ripete il ciclo finché non si arriva all'ultima riga. Solo allora avviene la sostituzione dei newline.

Insidie comuni

  • GNU contro BSD/macOS. Su macOS -i richiede un argomento obbligatorio (sed -i '' 's/a/b/' file) e molte estensioni GNU (\+, I, 1~2) non esistono. Per script portabili conviene restare su POSIX o richiedere esplicitamente GNU sed.
  • Virgolette. Usa gli apici singoli per evitare che la shell espanda $, \ e !. Se devi inserire una variabile shell passa agli apici doppi con cautela: sed "s/x/$VAR/". Se $VAR contiene / o &, la sostituzione si rompe.
  • Regex "greedy". s/<.*>// cancella dal primo < all'ultimo > della riga. Si risolve con una classe negata: s/<[^>]*>//g.
  • Regex base contro estese. In modalità base +, ?, |, ( e ) vanno protetti con la barra (\+), mentre con -E sono operatori diretti. È l'errore più frequente.
  • Non è un parser. Per HTML, JSON o XML meglio strumenti dedicati (jq, xmlstarlet, pup): sed lavora a righe e le strutture annidate lo mettono in crisi.
  • Prova prima di usare -i. Lancia il comando senza -i, oppure con -n e p, per controllare cosa verrebbe modificato.

Quando usare sed e quando altro

EsigenzaStrumento
Sostituzioni e filtri a rigased
Elaborazione per campi/colonne, calcoliawk
Sostituzione di singoli caratteritr
Ricerca di patterngrep
Logica complessa, strutture datiPython, Perl

sed ha una curva d'apprendimento ripida all'inizio, ma poche costruzioni (s///g, -n con p, d, gli indirizzi e -i) coprono la gran parte dei casi reali. È uno strumento piccolo, stabile da oltre cinquant'anni e presente su qualsiasi sistema Unix-like: esattamente il tipo di software libero che vale la pena conoscere a fondo.

Per approfondire: man sed, info sed (il manuale GNU, con un'ottima raccolta di esempi) e sed --help.