Sed

Chi non ha mai usato sed alzi la mano. Non c'è bisogno di dire che sed può essere ciò che noi vogliamo, può fare una quantità di cose ed è sicuramente indispensabile.
In questa roadmap vado a raccogliere gli esempi pratici che, nel tempo, mi capiteranno sotto mano.
[cos'è una roadmap]
Cos'è sed? sed è un manipolatore di contenuti testuali. Gli possiamo far cercare, modificare, sostituire contenuti all'interno di un file o di un flusso (tipo echo "qualcosa" | sed .... )
Mentre cercavo alcuni esempi sulle regular expression ho trovato questo file, scritto da Eric Pement (a cui vanno i miei sentiti ringraziamenti), che contiene una quantità smisurata di esempi su sed. E' talmente bello che ho pensato di tradurlo e di costruirci sopra una roadmap. Penso di pubblicare, prossimamente, degli esempi guidati basati sulla guida di Eric &C.
Ecco la traduzione completa. In fondo alla pagina c'è anche il link per scaricare il file in formato testuale, sia in inglese che in italiano.
------------------------------------------------------------------------- ESEMPI PER SED (Unix stream editor) Apr. 26, 2004
scritto da Eric Pement - pemente[at]northpark[dot]edu version 5.4
La ultima versione di questo file si trova normalmente qui:
http://sed.sourceforge.net/sed1line.txt
http://www.student.northpark.edu/pemente/sed/sed1line.txt
Questo file è anche disponibile in Portoghese qui:
http://www.lrv.ufsc.br/wmaker/sed_ptBR.html
Questo file è anche disponibile in Italiano qui:
http://www.squadrainformatica.com/files/sed1line_it.txt
RIGHE VUOTE: # riga vuota in un file sed G # riga vuota in un file che ha già delle linee vuote. Il file di output # non dovrebbe contenere più di una sola riga vuota tra due righe di testo sed '/^$/d;G' # doppia riga vuota in un file sed 'G;G' # elimina le righe vuote (assume che le righe dispari siano sempre vuote) sed 'n;d' # inserisce una riga vuota sopra ogni riga che verifica la "regex" sed '/regex/{x;p;x;}' # inserisce una riga vuota sotto ogni riga che verifica la "regex" sed '/regex/G' # inserisce una riga vuota sopra e sotto ogni riga che verifica la "regex" sed '/regex/{x;p;x;G;}' NUMERAZIONE: # numera ogni riga presente in un file (con allineamento a sinistra). Usa un <tab> (leggi # la nota su "\t" in fondo a questo file) al posto di uno spazio per preservare i margini sed = filename | sed 'N;s/\n/\t/' # numera ogni riga presente in un file (con allineamento a sinistra e a destra) sed = filename | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /' # numera ogni riga presente in un file, ma numera solo le righe non vuote sed '/./=' filename | sed '/./N; s/\n/ /' # conta le righe (emulando "wc -l") sed -n '$=' CONVERSIONE E SOSTITUZIONE DI TESTO: # IN AMBIENTE UNIX: converte il carattere "a capo" dal formato DOS a quello UNIX sed 's/.$//' # assume che tutte le righe finiscano con CR/LF sed 's/^M$//' # in bash/tcsh, premi Ctrl-V poi Ctrl-M sed 's/\x0D$//' # gsed 3.02.80, ma lo script sopra è piu facile # IN AMBIENTE UNIX: converte il carattere "a capo" (LF) dal formato unix al formato DOS sed "s/$/`echo -e \\\r`/" # linea di comando per ksh sed 's/$'"/`echo \\\r`/" # linea di comando per bash sed "s/$/`echo \\\r`/" # linea di comando per zsh sed 's/$/\r/' # gsed 3.02.80 # IN AMBIENTE DOS: converte il carattere "a capo" (LF) dal formato unix al formato DOS sed "s/$//" # metodo 1 sed -n p # metodo 2 # IN AMBIENTE UNIX: converte il carattere "a capo" (CR/LF) dal formato DOS a quello UNIX # Può essere fatto solo con UnxUtils sed, versione 4.0.7 or superiore. # Non può essere fatto con altre versioni dos di sed. Usa piuttosto "tr" sed "s/\r//" infile >outfile # UnxUtils sed v4.0.7 o superiore tr -d \r <infile >outfile # GNU tr versione 1.22 o superiore # elimina il carattere spazio (spazi, tabs) dall'inizio di ogni riga # allinea il testo a sinistra sed 's/^[ \t]*//' # leggi la nota su '\t' alla fine del file # elimina il carattere spazio (spazi, tabs) dalla fine di ogni riga sed 's/[ \t]*$//' # leggi la nota su '\t' alla fine del file # elimina sia qui spazi iniziali che quelli finali da ogni riga sed 's/^[ \t]*//;s/[ \t]*$//' # inserisce 5 spazi bianchi all'inizio di ogni riga (fa un'indentazione della pagina) sed 's/^/ /' # allinea il testo ad una larghezza di 79 colonne sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # fissa il 78esimo più uno spazio # centra il testo al centro della 79 colonne. Nel metodo 1 # gli spazi all'inizio della riga sono significativi, e quelli finali # sono appesi alla fine della riga. Nel secondo metodo, gli spazi # all'inizio della riga non sono considerati ai fini dell'allineamento, e # non vengono aggiunti gli spazi al termine della riga. sed -e :a -e 's/^.\{1,77\}$/ & /;ta' # metodo 1 sed -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/' # metodo 2 # sostituisce (trova e sostituisce) "foo" con "bar" per ogni riga sed 's/foo/bar/' # sostituisce solo la prima istanza trovata nella riga sed 's/foo/bar/4' # sostituisce solo le prime 4 istanze trovate nella riga sed 's/foo/bar/g' # sostituisce tutte le istanze trovate nella riga sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # sostituisce la penultima istanza sed 's/\(.*\)foo/\1bar/' # sostituisce l'ultima istanza # sostituisce "foo" con "bar" solo nelle righe che contengono "baz" sed '/baz/s/foo/bar/g' # sostituisce "foo" con "bar" ad eccezione delle righe che contengono "baz" sed '/baz/!s/foo/bar/g' # sostituisce "scarlet" o "ruby" o "puce" in "red" sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g' # la maggior parte dei sed gsed 's/scarlet\|ruby\|puce/red/g' # solo GNU sed # linee in ordine inverso (emula "tac") # un bug/caratteristica in HHsed v1.5 causa la non rimozione delle linee vuote sed '1!G;h;$!d' # metodo 1 sed -n '1!G;h;$p' # metodo 2 # inverte l'ordine dei caratteri in una riga (emula "rev") sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//' # accoda le righe pari a quelle dispari separandole con uno spazio (simile a "paste") sed '$!N;s/\n/ /' # se una riga finisce con backslash (\), appendile la linea successiva sed -e :a -e '/\\$/N; s/\\\n//; ta' # se una riga inizia con il segno uguale (=), appendila alla riga precedente # e rimpiazia "=" con un singolo spazio sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D' # aggiunge la virgola (,) alle stringhe numeriche, modificando "1234567" in "1,234,567" gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta' # GNU sed sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' # altri sed # aggiunge la virgola ai numeri con il punto decimale e con segno meno (GNU sed) gsed ':a;s/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g;ta' # aggiunge una riga vuota ogni 5 righe (dopo le righe 5, 10, 15, 20, etc.) gsed '0~5G' # solo GNU sed sed 'n;n;n;n;G;' # altri sed STAMPA SELETTIVA DI CERTE RIGHE: # stampa le prime 10 righe di un file (emula "head") sed 10q # stampa la prima riga di un file (emula "head -1") sed q # stampa le ultime 10 righe di un file (emula "tail") sed -e :a -e '$q;N;11,$D;ba' # stampa le ultime 2 righe di un file (emula "tail -2") sed '$!N;$!D' # stampa l'ultima riga di un file (emula "tail -1") sed '$!d' # metodo 1 sed -n '$p' # metodo 2 # stampa solo le linee che verificano la espressione regolare (emula "grep") sed -n '/regexp/p' # metodo 1 sed '/regexp/!d' # metodo 2 # stampa solo le linee che NON verificano la espressione regolare (emula "grep -v") sed -n '/regexp/!p' # metodo 1, corrisponde a sopra sed '/regexp/d' # metodo 2, sintassi più semplice # stampa la riga immediatamente precedente alla linea che verifica # la espressione regolare sed -n '/regexp/{g;1!p;};h' # stampa la riga immediatamente successiva alla linea che verifica # la espressione regolare sed -n '/regexp/{n;p;}' # stampa la riga immediatamente precedente e quella successiva alla linea che verifica # la espressione regolare (simile a "grep -A1 -B1") sed -n -e '/regexp/{=;x;1!p;g;$!N;p;D;}' -e h # cerca le righe contenenti AAA e BBB e CCC (in ogni ordine) sed '/AAA/!d; /BBB/!d; /CCC/!d' # cerca le righe contenenti AAA e BBB e CCC (nell' ordine) sed '/AAA.*BBB.*CCC/!d' # cerca le righe contenenti AAA o BBB o CCC (emula "egrep") sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # most seds gsed '/AAA\|BBB\|CCC/!d' # GNU sed only # stampa il paragrafo se contiene AAA (le righe vuote demarcano la separazione tra i paragrafi) # HHsed v1.5 deve avere una 'G;' dopo 'x;' nei prossimi 3 comandi. sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;' # stampa il paragrafo se contiene AAA e BBB e CCC (in ogni ordine) sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;/BBB/!d;/CCC/!d' # stampa il paragrafo se contiene AAA o BBB o CCC sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d gsed '/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d' # GNU sed only # stampa solo le righe lunghe almeno 65 caratteri sed -n '/^.\{65\}/p' # stampa solo le righe più corte di 65 caratteri sed -n '/^.\{65\}/!p' # metodo 1, corresponds to above sed '/^.\{65\}/d' # metodo 2, simpler syntax # stampa il contenuto del file compreso tra la linea che verifica l'espressione regolare e la fine del file sed -n '/regexp/,$p' # stampa il contenuto del file compreso fra le linee specificate (linee 8-12, incluse) sed -n '8,12p' # metodo 1 sed '8,12!d' # metodo 2 # stampa il contenuto alla riga 52 sed -n '52p' # metodo 1 sed '52!d' # metodo 2 sed '52q;d' # metodo 3, efficient on large files # cominciando dalla linea 3, stampa ciclicamente la settima riga successiva gsed -n '3~7p' # solo GNU sed sed -n '3,${p;n;n;n;n;n;n;}' # altri sed # stampa il contenuto del file compreso tra le righe che verificano le espressioni regolari indicate sed -n '/Iowa/,/Montana/p' # case sensitive CANCELLAZIONE SELETTIVA DI CERTE RIGHE: # stampa il contenuto del file ad eccezione di quanto compreso tra le righe che verificano le espressioni regolari indicate sed '/Iowa/,/Montana/d' # elimina le righe duplicate consecutive presenti in un file (emula "uniq"). # la prima riga di un set di linee duplicate viene mantenuta, le altre vengono eliminate sed '$!N; /^\(.*\)\n\1$/!P; D' # elimina le righe duplicate non consecutive presenti in un file. Fai attenzione a non eccedere la dimensione del buffer, oppure usa GNU sed. (?) sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' # elimina tutte le righe ad eccezione di quelle duplicate consecutivamente (emula "uniq -d"). sed '$!N; s/^\(.*\)\n\1$/\1/; t; D' # elemina le prime 10 righe di un file sed '1,10d' # elimina l'ultima riga di un file sed '$d' # elimina le ultime 2 righe di un file sed 'N;$!P;$!D;$d' # elimina le ultime 10 righe di un file sed -e :a -e '$d;N;2,10ba' -e 'P;D' # metodo 1 sed -n -e :a -e '1,10!{P;N;D;};N;ba' # metodo 2 # elimina ciclicamente l'ottava riga gsed '0~8d' # solo GNU sed sed 'n;n;n;n;n;n;n;d;' # altri sed # delete ALL blank lines from a file (same as "grep '.' ") sed '/^$/d' # metodo 1 sed '/./!d' # metodo 2 # delete all CONSECUTIVE blank lines from file except the first; also # deletes all blank lines from top and end of file (emula "cat -s") sed '/./,/^$/!d' # metodo 1, allows 0 blanks at top, 1 at EOF sed '/^$/N;/\n$/D' # metodo 2, allows 1 blank at top, 0 at EOF # elimina tutte le righe vuote consecutive presenti nel file ad eccezione delle prime 2: # (quindi si hanno al massimo 2 righe vuote consecutive) sed '/^$/N;/\n$/N;//D' # elimina tutte le righe vuote presenti ad inizio file sed '/./,$!d' # elimina tutte le righe vuote presenti alla fine del file sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' # funziona con tutte le versioni di sed sed -e :a -e '/^\n*$/N;/\n$/ba' # ditto (?), eccetto gsed 3.02* # elimina l'ultima riga di ogni paragrafo sed -n '/^$/{p;h;};/./{x;/./p;}' APPLICAZIONI SPECIALI: # rimuove nroff overstrikes (caratteri speciali?) (char, backspace) dalle man pages. Il comando 'echo' # può necessitare di un "-e" se utilizzi Unix System V o la bash shell [ sed "s/.`echo -e \\\b`//g" ] sed "s/.`echo \\\b`//g" # le doppie virgolette sono necessarie in ambiente unix sed 's/.^H//g' # in bash/tcsh, premi Ctrl-V e poi Ctrl-H per ottenere ^H sed 's/.\x08//g' # espressione esadecimale per sed v1.5 # mostra l'intestazione (header) di un messaggio Usenet o di una email sed '/^$/q' # elimina tutto ciò che è dopo la prima riga vuota # mostra il corpo (body) di un messaggio Usenet o di una email sed '1,/^$/d' # elimina tutto ciò che precede la prima riga vuota # mostra il Titolo del messaggio ma rimuove il "Subject: " iniziale sed '/^Subject: */!d; s///;q' # mostra l'indirizzo del mittente (From:) contenuto nell'intestazione del messaggio sed '/^Reply-To:/q; /^From:/h; /./d;g;q' # mostra l'indirizzo del mittente processando la prima riga dell'indirizzo di ritorno presente nell'header (cfr esempio precedente) [non chiaro] # testo originale: # parse out the address proper. Pulls out the e-mail address by itself # from the 1-line return address header (see preceding script) sed 's/ *(.*)//; s/>.*//; s/.*[:<] *//' # aggiunge ad inizio riga il simbolo "<" seguito da spazio per ciacuna riga del file (quota il messaggio) sed 's/^/> /' # rimuove da inizio riga il simbolo "<" seguito da spazio per ciacuna riga del file ("un-"quota il messaggio) sed 's/^> //' # rimuove la maggiorparte dei tag HTML (vale anche per tag multilinea) sed -e :a -e 's/<[^>]*>//g;/</N;//ba' # estrae le parti binarie uuencoded, rimuovendo le parti estranee in modo che risultino solo le parti binarie uuencoded # i file devono essere passati nel corretto ordine. # la versione 1 può essere usata da riga di comando, mentre la versione 2 può essere utilizzata all'interno di script di bash # (Modificato da uno script di Rahul Dhesi.) sed '/^end/,/^begin/d' file1 file2 ... fileX | uudecode # vers. 1 sed '/^end/,/^begin/d' "$@" | uudecode # vers. 2 # comprime individualmente in formato zip ogni file con estensione .TXT presente nella directory, # eliminando il file sorgente e rinomina ogni file .ZIP con il nome del file .TXT di origine. # (under DOS: the "dir /b" switch returns bare filenames in all caps). (?) echo @echo off >zipup.bat dir /b *.txt | sed "s/^\(.*\)\.TXT/pkzip -mo \1 \1.TXT/" >>zipup.bat USO TIPICO: # Sed riceve uno o più comandi e li applica tutti i sequenza per ciascuna linea di input (l'input può essere ad es. un file di testo) # Dopo che tutti i comandi sono stati applicati alla prima riga di input, il risultato viene inviato in output # e viene processata la successiva riga di input e il ciclo si ripete. # Gli esempi precedenti assumono che l'input arrivi dallo standard input (ad es. in console può essere usata la pipe: cat file | ...) # Uno o più files possono essere accodati al comando se l'input non arriva dallo standard input. (sed [opts - cmds] file1 file2 ...) # L'output prodotto da sed viene inviato allo standard out. Esempi: cat filename | sed '10q' # usa la pipe come input sed '10q' filename # stessa cosa, ma senza l'uso di cat sed '10q' filename > newfile # redirige l'output in un file # Per istruzioni aggiuntive sulla sintassi, inclusi i modi per applicare # comandi da un file su disco anziche dalla riga di comando, consulta # "sed & awk, 2nd Edition," di Dale Dougherty e Arnold Robbins (O'Reilly, # 1997; http://www.ora.com), "UNIX Text Processing," di Dale Dougherty # and Tim O'Reilly (Hayden Books, 1987) o le guide di Mike Arst # distribuite nel file U-SEDIT2.ZIP (presente su molti siti). # Per scoprire tutte le potenzialità di sed devi conoscere le "espressioni regolari." Per questo cfr # "Mastering regular expressions" by Jeffrey Friedl (O'Reilly, 1997). # Il manuale ("man page") presente sui sistemi unix può essere utile (prova "man # sed", "man regexp", o la sottosezione sulle espressioni regolari presente in "man # sed"), anche se le man pages sono notoriamente ostiche. Non sono scritte nell'ottica di insegnare # ad usare sed o le espressioni regolari ai novizi, ma come manuale di supporto per chi sa già come # usare questi strumenti. SINTASSI DELLE VIRGOLETTE: # Gli esempi precedenti usano le apici singole ('...') # piuttosto che le doppie apici ("...") # per contenere i comandi di modifica perchè sed è usato tipicamente in ambiente unix. # I singoli apici impediscono che la shell uni interpreti il simbolo $ e le questi apici (`...`), # che vengono invece interpretati dalla shell se sono contenuti nelle doppie apici. # Gli utenti della "csh" shell e derivate necessitano di quotare anche il punto esclamativo (!) con la backslash (\!) # per poter eseguire gli esempi riportati sopra, anche se vengono impiegati gli apici singoli. # Le versioni di sed per DOS invece richiedono le doppie apici ("...") al posto del singolo apice per racchiudere i # comandi di modifica. USO DI "\t" NEGLI SCRIPT SED: # Per chiarezza di documentazione, negli esempi abbiamo usato l'espressione '\t' # per indicare il carattere TAB (0x09). # Però la maggior parte delle versioni di sed non riconoscono l'abbreviazione '\t', # perciò mentre scrivi gli esempi da riga di comando dovresti premere il tasto TAB # anzichè scrivere '\t'. # L'uso di '\t' è invece supportato nelle espressioni regolari e come meta-carattere in # awk, perl, HHsed, sedmod, e GNU sed v3.02.80.
VERSIONI DI SED: # Le versioni di sed differisco fra loro e ci si deve aspettare piccole # variazioni di sintassi tra una versione e l'altra. # In particolare, la maggior parte non supporta l'uso delle etichette (labels) # (:nome) o l'uso di comandi separati (b,t) all'interno di comandi di modifica. # Abbiamo cercato di usare la sintassi più portabile per la maggior parte degli # utenti di sed, anche se le più popolari versioni GNU di sed consento sintassi # più succinte. # Quando il lettore vede sintassi piuttosto lunghe di questo tipo: sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # è incoraggiato a sapere che GNU sed lo lascia ridurre a: sed '/AAA/b;/BBB/b;/CCC/b;d' # o anche sed '/AAA\|BBB\|CCC/b;d' # In aggiunta, ricorda che mentre alcune versioni di sed accettano un comando come "/one/ s/RE1/RE2/" # , altre non consentono "/one/! s/RE1/RE2/" # , che contiene uno spazio prima della 's'. Ometti lo spazio scrivendo il comando. OTTIMIZZAZIONI PER LA VELOCITA:
# Se è necessario incrementare la velocità di esecuzione (per esempio a causa di grandi # volumi di dati in input o di processore e disco lento), la sostituzione sarà eseguita # più velocemente se l'espressione da cercare è specificata prima dell'istruzione "s/.../.../". # Cioè: sed 's/foo/bar/g' filename # comune comando di sostituzione sed '/foo/ s/foo/bar/g' filename # esegue più velocemente sed '/foo/ s//bar/g' filename # sintassi più succinta # In caso di selezione o eliminazione di righe che sono presenti solo nella # prima parte di file, l'uso di del comando "quit" (q) nello script # ridurrà drasticamente il tempo di elaborazione per grandi file. # Cioè: sed -n '45,50p' filename # stampa le righe dalla 45 alla 50 sed -n '51q;45,50p' filename # lo stesso, ma molto più velocemente # Se hai script addizionali per contribuire a questo documenti o se se scopri errori, # perfavore invia una mail. Indica la versione di sed in uso, il sistema operativo # per il quale è stato compilato e la natura del problema. # Vari script presenti nel documento sono stati scritti o modificati da: Al Aab <af137@freenet.toronto.on.ca> # moderatore della lista "seders"
Edgar Allen <era@sky.net> # vari
Yiorgos Adamopoulos <adamo@softlab.ece.ntua.gr>
Dale Dougherty <dale@songline.com> # autore of "sed & awk"
Carlos Duarte <cdua@algos.inesc.pt> # autore di "do it with sed"
Eric Pement <pemente@northpark.edu> # autore di this document
Ken Pizzini <ken@halcyon.com> # autore di GNU sed v3.02
S.G. Ravenhall <stew.ravenhall@totalise.co.uk> # eccellente de-html script
Greg Ubben <gsu@romulus.ncsc.mil> # molti contributi e molti aiuti
-------------------------------------------------------------------------
Ora che ho tradotto la guida comincio a raccogliere qua sotto delle sintassi di esempio:
- eliminare tutte le righe vuote presenti in un file:
cat file.txt | sed '/^$/d;' opp sed '/^$/d;' -i file.txt
- eliminare da una stringa tutto quello che sta prima di un certo carattere (ad es. #) anche se ripetuto N volte
echo "11sa#ewwew#ciao" | sed -e 's/.*#//g';
ottengo
ciao
| Attachment | Size |
|---|---|
| <p>sed1line_it.txt</p> | 19.91 KB |
| <p>sed1line_en.txt</p> | 17.72 KB |
- dam's blog
- 5484 reads
Printer-friendly version


















Comments
Bel lavoro, ottimo!
Bel lavoro, ottimo!
grassie! :-D
-- Dam
Più che un commento(++++), una domanda.
mi sono permesso di
mi sono permesso di rieditare il tuo post in modo che il codice fosse visibile
secondo il tuo esempio, tu vorresti rimuovere l'invio a capo a posteriori di tutti i tag TAG_A_1 e precenti tutti i tag /TAG_A_1
dico bene?
se è cosi confermamelo, appena ho un istante faccio una prova
ciao!
-- Dam
Corretto
Innanzitutto grazie per la risposta.
Si esatto,
ho bisogno di mettere i dati dell'XML e i tag che li contengono sulla stessa linea.
Mentre gli altri tag in linee diverse. Non sono necessarie indentazioni.
Grazie ancora.
Post new comment