Introduzione
Abbastanza spesso quando si lavora con file di testo è necessario trovare e sostituire stringhe di testo in uno o più file.
sed
è una stream editor. Può eseguire manipolazioni di testo di base su file e flussi di input come pipeline. Con sed
puoi cercare, trovare e sostituire, inserire ed eliminare parole e righe. Supporta espressioni regolari di base ed estese che consentono di abbinare modelli complessi.
In questo articolo, parleremo di come trovare e sostituire le stringhe con sed
. Ti mostreremo anche come eseguire una ricerca ricorsiva e sostituirla.
Trova e sostituisci
Esistono diverse versioni di sed
, con alcune differenze funzionali tra loro. macOS utilizza la versione BSD e la maggior parte delle distribuzioni Linux viene fornita con GNU sed
preinstallato di default. Useremo la versione GNU.
La forma generale di ricerca e sostituzione del testo utilizzando sed
assume la forma seguente:
sed -i 's/SEARCH_REGEX/REPLACEMENT/g' INPUTFILE
-i
- Per impostazione predefinitased
scrive l'output nell'output standard. Questa opzione indicased
di modificare i file in atto. Se viene fornita un'estensione (ex -i.bak) verrà creato un backup del file originale.s
- Il comando sostitutivo, probabilmente il comando più utilizzato in sed./ / /
- Carattere delimitatore. Può essere qualsiasi carattere ma di solito viene utilizzato il carattere slash (/
).SEARCH_REGEX
- Stringa normale o espressione regolare da cercare.REPLACEMENT
- La stringa di sostituzione.g
- Flag di sostituzione globale. Per impostazione predefinita,sed
legge il file riga per riga e modifica solo la prima occorrenza diSEARCH_REGEX
su una riga. Quando viene fornito il flag di sostituzione, tutte le occorrenze verranno sostituite.INPUTFILE
- Il nome del file su cui si desidera eseguire il comando.
È buona norma inserire virgolette attorno all'argomento in modo che i meta-characters della shell non si espandano.
Vediamo esempi su come utilizzare il comando sed
per cercare e sostituire il testo nei file con alcune delle sue opzioni e flag più comunemente utilizzate.
A scopo dimostrativo, utilizzeremo il seguente file file.txt:
123 Foo foo foo
foo /bin/bash Ubuntu foobar 456
Se si omette il flag g
, verrà sostituita solo la prima istanza della stringa di ricerca in ciascuna riga:
sed -i 's/foo/linux/' file.txt
123 Foo linux foo
linux /bin/bash Ubuntu foobar 456
Con il flag di sostituzione globale sed
sostituisce tutte le occorrenze del modello di ricerca:
sed -i 's/foo/linux/g' file.txt
123 Foo linux linux
linux /bin/bash Ubuntu linuxbar 456
Come avrai notato, nell'esempio precedente viene sostituita anche la sottostringa foo
all'interno della stringa foobar
. Se questo non è il comportamento desiderato, utilizzare l'espressione word-boundery (\b
) su entrambe le estremità della stringa di ricerca. Questo assicura che le parole parziali non siano abbinate.
sed -i 's/\bfoo\b/linux/g' file.txt
123 Foo linux linux
linux /bin/bash Ubuntu foobar 456
Per rendere insensibile la corrispondenza del motivo, utilizzare il flag I
. Nell'esempio riportato di seguito stiamo usando sia il flag g
che il flag I
:
sed -i 's/foo/linux/gI' file.txt
123 linux linux linux
linux /bin/bash Ubuntu linuxbar 456
Se vuoi trovare e sostituire una stringa che contiene il carattere delimitatore (/
) dovrai usare la barra rovesciata (\
) per sfuggire alla barra. Ad esempio, per sostituire /bin/bash
con /usr/bin/zsh
te sarebbe usare
sed -i 's/\/bin\/bash/\/usr\/bin\/zsh/g' file.txt
L'opzione più semplice e molto più leggibile è usare un altro carattere delimitatore. Molte persone usano la barra verticale pipe |
o i due punti :
ma puoi usare qualsiasi altro carattere:
sed -i 's|/bin/bash|/usr/bin/zsh|g' file.txt
123 Foo foo foo
foo /usr/bin/zsh Ubuntu foobar 456
Puoi anche usare espressioni regolari. Ad esempio, per cercare tutti i numeri di 3 cifre e sostituirli con la stringa number
useresti:
sed -i 's/\b[0-9]\{3\}\b/number/g' file.txt
number Foo foo foo
foo /bin/bash demo foobar number
Un'altra caratteristica utile di sed è che puoi usare il carattere e commerciale &
che corrisponde al modello abbinato. Il personaggio può essere usato più volte.
Ad esempio, se si desidera aggiungere parentesi graffe {}
attorno a ciascun numero di 3 cifre, digitare:
sed -i 's/\b[0-9]\{3\}\b/{&}/g' file.txt
{123} Foo foo foo
foo /bin/bash demo foobar {456}
Ultimo ma non meno importante, è sempre una buona idea fare un backup quando si modifica un file sed
. Per fare ciò basta fornire un'estensione per l'opzione -i
. Ad esempio, per modificare file.txt
e salvare il file originale come file.txt.bak
si usa:
sed -i.bak 's/foo/linux/g' file.txt
Se si desidera assicurarsi che il backup sia stato creato, elencare i file con il comando ls
:
ls
file.txt file.txt.bak
Trova e sostituisci ricorsivo
A volte si desidera cercare ricorsivamente nelle directory i file contenenti una stringa e sostituire la stringa in tutti i file. Questo può essere fatto usando comandi come find
o grep
per trovare ricorsivamente i file nella directory e reindirizzare i nomi dei file sed
.
Il seguente comando cercherà ricorsivamente i file nella directory di lavoro corrente e passerà i nomi dei file in sed
.
find . -type f -exec sed -i 's/foo/bar/g' {} +
Per evitare problemi con i file che contengono spazio nei loro nomi, utilizzare l'opzione -print0
che indica al comando find
di stampare il nome del file, seguito da un carattere null e reindirizzare l'output verso sed
utilizzando xargs -0
:
find . -type f -print0 | xargs -0 sed -i 's/foo/bar/g'
Per escludere una directory utilizzare l'opzione -not -path
. Ad esempio, se si sta sostituendo una stringa nel repository git locale per escludere tutti i file che iniziano con dot (.
), utilizzare:
find . -type f -not -path '*/\.*' -print0 | xargs -0 sed -i 's/foo/bar/g'
Se si desidera cercare e sostituire il testo solo su file con estensione specifica, utilizzare:
find . -type f -name "*.md" -print0 | xargs -0 sed -i 's/foo/bar/g'
Un'altra opzione è utilizzare il comando grep
per trovare ricorsivamente tutti i file contenenti il modello di ricerca e quindi reindirizzare i nomi dei file a sed
:
grep -rlZ 'foo' . | xargs -0 sed -i.bak 's/foo/bar/g'
Conclusione
Per saperne di più sui comandi sed
, opzioni e flag, visita il manuale GNU sed.