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:
- legge la riga e la copia nel pattern space, un buffer di lavoro;
- esegue sul pattern space tutti i comandi dello script, in ordine;
- stampa il pattern space (a meno che non si usi
-n); - 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
| Opzione | Significato |
|---|---|
-n | non stampa automaticamente il pattern space (si stampa solo con p) |
-e SCRIPT | aggiunge uno script; si può ripetere più volte |
-f FILE | legge 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) |
-s | tratta ogni file come flusso separato (utile con $ e numeri di riga) |
-z | usa il carattere nullo come separatore di riga invece del newline |
Indirizzi
| Indirizzo | Significato |
|---|---|
5 | riga 5 |
$ | ultima riga |
3,8 | righe 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~2 | una riga ogni due, a partire dalla prima (GNU) |
5,+3 | riga 5 e le 3 successive (GNU) |
indirizzo! | nega la selezione |
Comandi più usati
| Comando | Azione |
|---|---|
s/re/sost/flag | sostituzione |
d | cancella il pattern space e passa alla riga successiva |
p | stampa il pattern space |
i\testo | inserisce testo prima della riga |
a\testo | aggiunge testo dopo la riga |
c\testo | sostituisce l'intera riga con il testo |
y/abc/xyz/ | traslittera i caratteri (come tr) |
= | stampa il numero di riga |
q | esce subito |
n / N | legge la riga successiva (sostituendo / accodando al pattern space) |
h H g G x | copiano, accodano e scambiano tra pattern space e hold space |
Il comando s in dettaglio
È di gran lunga il comando più usato:
s/espressione/sostituzione/flagI flag più comuni sono:
g: sostituisce tutte le occorrenze nella riga (senza, solo la prima);N: sostituisce solo l'N-esima occorrenza;ioI: 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.conf2. 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.txt3. 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.conf4. 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_configCon -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.conf6. 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.txt7. 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.log8. 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.sqlAttenzione 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.txtIl 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
-irichiede 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$VARcontiene/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-Esono 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-nep, per controllare cosa verrebbe modificato.
Quando usare sed e quando altro
| Esigenza | Strumento |
|---|---|
| Sostituzioni e filtri a riga | sed |
| Elaborazione per campi/colonne, calcoli | awk |
| Sostituzione di singoli caratteri | tr |
| Ricerca di pattern | grep |
| Logica complessa, strutture dati | Python, 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.