Ad oggi non esiste sistema GNU/Linux che non sia dotato delle utility di elaborazione di testo: sed, awk. In specifico, in questo post si tratterà una panoramica generale su sed.
Cos’è:
Sed è un editor che si occupa della manipolazione di file di testo in modalità non interattiva. Come tutti gli editor di testo tale manipolazione opera attraverso la modifica e trasformazione di un file. La differenza però con gli editor comuni sta nel fatto che sed opera in standard non interattivo ed agisce in ordine: ricevendo un testo/file/stdin come input che poi sarà opportunamente trattato/modificato attraverso i parametri scelti con la specificazione delle righe, una alla volta; terminata questa fase si preoccuperà di inviare il risultato ad un file/stdout. Sostanzialmente più che un editor vero e proprio funge da filtro trasformatore.
NB: l’utilizzo di sed in tutte le sue varianti presuppone una discreta/media conoscenza delle regexp. A tal proposito è consigliata la lettura del post relativo; le espressioni regolari: regexp.
Sintassi del comando:
~$ sed --h NB: sono elencate e commentate le opzioni generali di utilizzo. In specifico, le ritenute fondamentali. -n, --quiet, --silent # evita che venga mostrato ciò che viene fatto "modalità silent" (uguale al parametro --quiet e/o -n) -e script, --expression=script # aggiunge lo script definito da riga di comando ai comandi da eseguire. Script definito all'interno degli apici '' e/o "" (più comandi sono separati dal punto e virgola ";") -f script.sh, --file=script.sh # aggiunge questa volta il contenuto del file script.sh ai comandi da eseguire.
-i[SUFFIX], --in-place[=SUFFIX] # scriverà il risultato direttamente sul file originale modificandolo. NB: l'opzione -i può essere associata ad un suffisso che verrà preso in considerazione per creare un file backup come dagli esempi: sed -i # modificherà il file originario senza creare alcun backup sed --in-place # identico all'esempio precedente -i sed -i.backup # modificherà il file originario creando salvando una copia di backup dello stesso sed --in-place=.backup # come l'esempio precedente -i.backup
Comandi operatori:
NB: sed tende a suddividere i comandi generali secondo due categorie. La prima definisce quali e che tipo di operazioni eseguire. La seconda categoria invece racchiude le righe su cui operare e quindi delle specifiche delle stesse in termini di numero riga, classe, etc. Analizziamo in dettaglio:
p # "print" stampa la riga o il file
NB: Questa opzione è particolare. Per comprenderla analizzare gli esempi seguenti: sed -e '' file # stampa il file e non esegue nessuna operazione definita negli apici '' sed -n -e '' file # non esegue nessuna operazione e non stampa il file (opzione -n) sed -e 'p' file # stampa il file "operazione definita da p" (ogni riga trovata due volte) sed -n -e 'p' file # come sopra ma questa volta associa l'operazione print alla modalità silent (stampa quindi una sola volta ogni riga)
d # "delete" elimina la riga /regexp/p # stampa solo le righe corrispondenti alla regexp espressa /regexp/d # elimina solo le righe corrispondenti alla regexp espressa
s/testo/sostituzione/ # sostituisce la stringa "testo" con "sostituzione" y/abcd/ABCD/ # come sopra ma analizza tutti i caratteri presi come riferimento nel modello1 "abcd" con i corrispondenti del modello2 "ABCD". Opera in sostituzione solo sui caratteri corrispondenti. Nell'esempio da abcd minuscolo a MAIUSCOLO. g # definisce il parametro "global". Agisce su tutte le verifiche d'occorrenza di ogni riga trovata.Utile nelle sostituzioni recursive su più righe e/o per lasciare inalterate il resto delle righe (vedi più avanti nel post). s/testo/sostituzione/g # sostituisce tutte le parole testo con sostituzione. Agisce su tutto il file e non si ferma solo alla prima riga trovata.
NB: l’ordine di suddivisione comandi vi risulterà inverso a quello descritto precedentemente. Ma vi rendererà il tutto di più facile comprensione.
Selettori di riga e specifiche operatori:
3 # corrisponde alla terza riga 3p # stampa la terza riga di default due volte e il resto una sola volta (se associato ad opzione -n precedentemente descritta la stamperà una sola volta) , # "virgola" corrisponde al range da prima a dopo il simbolo. Esempio: 1,3 (le righe da 1 a 3) ~ # "infinito" è usato per definire ciò che c'è prima come partenza e ciò che c'è dopo come fine. Esempio: 1~3 (parte da riga 1 e poi ogni 3)
Esempi comandi,selettori di riga e specifiche operatori:
1,4d # le prime quattro righe sono eliminate 2,4d # le righe da 2 a 4 sono eliminate 5,10p # le righe da 5 a 10 sono stampate 1~2p # le righe dispari sono stampate (parte dalla prima riga e poi ogni due) 2~2p # le righe pari sono stampate (parte dalla seconda riga e poi ogni due) 4~3p # stampa le righe 4 7 10 13 ... etc (parte dalla quarta riga e poi ogni 3) 4~4d # elimina le righe 4 8 12 16 ... etc (parte dalla quarta riga e poi ogni 4) /regexp/,/regexp-sost/p # stampa tutte le righe comprese tra la prima regexp espressa e la seconda. 2~2s/pippo/PIPPO/g # sostituisce la parola pippo con PIPPO ma solo agendo sulle righe pari.Come da esempio la prima parte definisce le righe e la seconda l'operazione. /^$/d # cancella tutte le righe vuote /Pippo/p # stampa tutte le righe in cui è presente Pippo (da usare con opzione -n) /PIPPO/d # cancella tutte le righe in cui è presente PIPPO e procede alla cancellazione del resto della riga in cui è presente la parola s/PIPPO//g # cancella la parola PIPPO in ogni riga sostituendola con nulla e lasciando il resto della riga intatto. IMPORTANTE: questo esempio di doppio slash applicato alla frase seguente chiarisce il significato di una sostituzione applicata con nulla seguita dal simbolo g "global" che lascierà intatto il resto della riga.
NB: L’espressione di tipo s/PIPPO,//g nella riga io adoro PIPPO, pluto e paperone opportunamente creata modificherà la frase in modo da risultare come io adoro pluto e paperone.
Prova su campo con sed:
~$ echo io adoro PIPPO, pluto e paperone >> prova.txt ~$ cat prova.txt io adoro PIPPO, pluto e paperone ~$ sed -i -e 's/PIPPO,//g' prova.txt ~$ cat prova.txt io adoro pluto e paperone
NB: i più temerari ricorderanno leggendo il post precedente su regexp che spesso poteva capitare di dover usufruire dello slash / come simbolo da ricercare che quindi era considerato come un carattere speciale (come lo possono essere il punto,la virgola,etc) e che quindi per arrivare allo scopo era necessario utilizzare lo slash rovesciato ”“ seguito dal carattere speciale da ricercare. Ovviamente in molte regexp di tipo sostitutivo ‘s// ‘ potrebbe risultare fastidioso quindi scrivere continuamente / per effettuare una sostituzione come lo era l’esempio:
s/Linux/GNU/Linux/g # lo slash rovesciato tratta il seguente slash normale / come un carattere speciale. Altrimenti sarebbe considerato come fine regexp.Sostituzione della parola Linux con GNU/Linux in ogni riga.
Per evitare questa cosa si può scegliere di sostituire gli slash con altri limitatori come ad esempio i due punti “ : “come da esempio seguente.
s:regexp:sostituzione:g In specifico per provare creaiamo un file prova.txt come da esempio: ~$ echo Linux >> prova.txt ~$ cat prova.txt Linux ~$ sed -i -e 's:Linux:GNU/Linux:g' prova.txt ~$ cat prova.txt GNU/Linux
Considerazioni: come sempre è utile capire che la potenza è nascosta nelle cose apparentemente banali. Bisogna tener conto che l’utilizzo di sed è fondamentale per la creazione di una pipe e che molto spesso è associato ad altre utility del suo genere per operazioni complesse all’interno di scripts. Il miglior modo per imparare quindi è come al solito: cominciare e provare, provare, provare. Saluti.
NB: questo post è una sorta di sommario e di appunti e quindi i riferimenti e la linea generale di trattamento del post, come nel precedente su regexp, sono legati al link ufficiale di riferimento su Advanced Bash-Scripting Guide.
# End