Pagina 1 di 2

sed: individuare occorrenze multiple

Inviato: mar 9 nov 2010, 12:46
da ZeroUno
Ho una singola riga in cui dentro ci sono dei blocchetti facilmente intercettabili da una semplice espressione regolare. I blocchetti sono separati da un testo altamente irregolare.
Ho bisogno di una sed che mi elimini tutto questo testo separatore e mi lasci i blocchetti separati da uno spazio o qualcos'altro.

Esempio:
ciao123a-tutti456-help@me789grazie_01

i blocchetti saranno intercettati dall'espressione [0-9]{3}, quindi l'output dovrà essere
123 456 789

ovviamente il testo e i blocchetti sono più complessi, ma l'importante è che per quanto possano essere complessi l'espressione regolare è costruibile. Il numero di occorrenze non è noto a priori.

Ho fatto un po' di prove ma proprio non sono riuscito a venirne a capo.

01

Re: sed: individuare occorrenze multiple

Inviato: mar 9 nov 2010, 13:52
da umaga
ho provato questo semplice grep sulla tua stringa di esempio:

a=ciao123a-tutti456-help@me789grazie_01
echo $a | grep -oe '[0-9][0-9][0-9]'

l'output è stato:
123
456
789

Re: sed: individuare occorrenze multiple

Inviato: mar 9 nov 2010, 14:41
da ZeroUno
ottimo, grazie. Quello che mi stupisce di quella grep è che le entry le restituisce su righe diverse quando si trovano invece tutte sulla stessa riga


Io avevo risolto in un modo un po' più astruso:
1) con sed aggiungi un "|" prima e dopo la regexpa
2) con awk prendi solo i campi $2,$4,$6...

echo ciao123a-tutti456-help@me789grazie_01|sed -r -e 's#/([0-9]{3})#|\1|#ig'|awk -F"|" '{a=2;while($(a)){print $(a);a=a+2}}'

Re: sed: individuare occorrenze multiple

Inviato: mar 9 nov 2010, 16:33
da targzeta
Preferisco anche io grep, se vuoi l'output tra spazi invece che tra newline:

Codice: Seleziona tutto

echo ciao123a-tutti456-help@me789grazie_01|grep -o '[0-9]\{3\}'|tr -s '\n' ' '
Emanuele

Re: sed: individuare occorrenze multiple

Inviato: mer 10 nov 2010, 0:03
da ZeroUno
quel tr fatto così sicuramente mi servirà per qualche cosa (tr non me lo sono mai studiato a fondo così come anche altri) ma per la separazione tra spazi di solito faccio

Codice: Seleziona tutto

echo $(echo ciao123a-tutti456-help@me789grazie_01|grep -o '[0-9]\{3\}')
comunque io ne ho bisogno in un for

Codice: Seleziona tutto

for x in $(echo ciao123a-tutti456-help@me789grazie_01|grep -o '[0-9]\{3\}');do ...
e sicuramente per tutti gli altri tipi di uso di questo caso avrò la convenienza della suddivisione in newline.


A questo putto approfitto per un quesito sul newline. Avendo una lista del tipo
a
b
c
a
d
a
e
f
g
a
h
i
vorrei in output
a b
c
a d
a e
f
g
a h
i

cioè se trovo la stringa 'a' allora unisci con la riga successiva del file (ovviamente 'a' può essere una regex ma è secondario). io risolvevo con una soluzione non proprio performate ma funzionate; qualcosa tipo:

Codice: Seleziona tutto

cat file.txt|while read x;do echo $x|grep -q 'a' &&echo -n "$x "||echo $x;done
nel caso più semplice. questo l'ho abbozzato in questo istante e presenta bug, ma spiega il concetto.
c'è una soluzione più rapida?

Ciao
01

Re: sed: individuare occorrenze multiple

Inviato: mer 10 nov 2010, 9:43
da targzeta
Puoi usare questo:

Codice: Seleziona tutto

sed -n '/^a/{N;s/\n/ /;};p;' file.txt
Emanuele

P.S. Per leggere tutte le righe di un file si può anche usare:

Codice: Seleziona tutto

for row in $(<file.txt)

Re: sed: individuare occorrenze multiple

Inviato: gio 11 nov 2010, 13:18
da ZeroUno
spina ha scritto:Puoi usare questo:

Codice: Seleziona tutto

sed -n '/^a/{N;s/\n/ /;};p;' file.txt
Grazie,
P.S. Per leggere tutte le righe di un file si può anche usare:

Codice: Seleziona tutto

for row in $(<file.txt)
non si comporta correttamente in caso file.txt contiene spazi.

Re: sed: individuare occorrenze multiple

Inviato: gio 11 nov 2010, 19:13
da targzeta
ZeroUno ha scritto:
spina ha scritto:P.S. Per leggere tutte le righe di un file si può anche usare:

Codice: Seleziona tutto

for row in $(<file.txt)
non si comporta correttamente in caso file.txt contiene spazi.
Esatto. Per essere più precisi non si comporta bene quando le righe contengono i caratteri dell'IFS che possono essere diversi dal classico:

Codice: Seleziona tutto

$> set| grep IFS
IFS=$' \t\n'
Quindi basterebbe anche fare un:

Codice: Seleziona tutto

(IFS=$'\n'; for row in $(<file.txt); do ...done)
ma alla fine forse è meglio usare il comando read come fai tu.

Emanuele

Re: sed: individuare occorrenze multiple

Inviato: ven 12 nov 2010, 13:49
da ZeroUno
spina ha scritto:Quindi basterebbe anche fare un:

Codice: Seleziona tutto

(IFS=$'\n'; for row in $(<file.txt); do ...done)
ma alla fine forse è meglio usare il comando read come fai tu.
L'unico problema è quando ci deve essere interattività con l'utente:
lista.txt

Codice: Seleziona tutto

dimmi il tuo nome
dimmi il tuo cognome
dimmi la tua età

Codice: Seleziona tutto

cat lista |while read a;do
  echo $a
  read b
  echo $b
done
chiaramente questo codice non funziona.

Re: sed: individuare occorrenze multiple

Inviato: ven 12 nov 2010, 14:26
da targzeta
Sotto questo punto di vista allora è meglio il mio comando. Tra l'altro il tuo comando soffre anche quando un file non ha un '\n' nell'ultima riga:

Codice: Seleziona tutto

$> cat -e lista.txt 
dimmi il tuo nome$
dimmi il tuo cognome$
dimmi la tua età

$>  cat lista.txt| while read a;do echo $a; done
dimmi il tuo nome
dimmi il tuo cognome
L'errore del '\n' finale non lo si può eliminare dato che è intrinseco al comando 'read' che non trova il fine linea, o almeno io credo che non lo si possa eliminare. Mentre il caso particolare che citavi tu lo si può evitare facendo:

Codice: Seleziona tutto

$> cat lista.txt|while read a;do echo $a; read -u 2 b; echo $b; done
non mi chiedere perchè funziona perchè non lo so, io cercavo di mandare l'output di cat verso lo standard error e mettere in 'a' la lettura dallo stderr. Non ci sono riuscito ma tra le prove ho notato che questo funziona. E' come se tutti e tre i file descriptor siano aperti nella console (infatti funziona anche se al posto di '-u 2' ci metti '-u 1').

Emanuele

Re: sed: individuare occorrenze multiple

Inviato: ven 12 nov 2010, 20:28
da ZeroUno
prima o poi leggerò il man di bash dall'inizio alla fine parola per parola. ogni volta che lo apro scopro una cosa nuova.
spina ha scritto: Tra l'altro il tuo comando soffre anche quando un file non ha un '\n' nell'ultima riga
Ho scritto quel codice al volo direttamente sul forum, senza passarlo per la shell
Ma il caso del mancato eol alla fine del file non l'ho proprio tenuto in considerazione perchè il 99,999% dei miei file ce l'hanno tutti visto che uso vi/vim
il restante 0,001% deriva da quei file volutamente creati con echo -n

Ciao
01

Re: sed: individuare occorrenze multiple

Inviato: sab 13 nov 2010, 16:19
da Mario Vanoni

Codice: Seleziona tutto

[$> cat -e lista.txt
dimmi il tuo nome$
dimmi il tuo cognome$
dimmi la tua età

$
awk '/./ {print} lista.txt
risolve il problema
/./ significa almeno un carattere.

Re: sed: individuare occorrenze multiple

Inviato: ven 26 nov 2010, 15:42
da ZeroUno
Posso sostituire

Codice: Seleziona tutto

awk -F'\n' '{if($1 ~ /^ /){s=s gensub(/^ +/,"",1)}else{print s;s=$1}}END{print s}' nomefile
con qualcosa di più decente?


Per capire cosa fa:

Codice: Seleziona tutto

$ cat nomefile
riga1
riga2
riga3a
  riga3b
riga4
riga5a
  riga5b
  riga6c
riga7
output

Codice: Seleziona tutto

riga1
riga2
riga3ariga3b
riga4
riga5ariga5briga6c
riga7

Re: sed: individuare occorrenze multiple

Inviato: ven 26 nov 2010, 17:10
da Mario Vanoni
ZeroUno ha scritto:Posso sostituire

Codice: Seleziona tutto

awk -F'\n' '{if($1 ~ /^ /){s=s gensub(/^ +/,"",1)}else{print s;s=$1}}END{print s}' nomefile
con qualcosa di più decente?


Per capire cosa fa:

Codice: Seleziona tutto

$ cat nomefile
riga1
riga2
riga3a
  riga3b
riga4
riga5a
  riga5b
  riga6c
riga7
output

Codice: Seleziona tutto

riga1
riga2
riga3ariga3b
riga4
riga5ariga5briga6c
riga7
root@va2:~# awk '/./ {print $1}' nomefile

Codice: Seleziona tutto

riga1
riga2
riga3a
riga3b
riga4
riga5a
riga5b
riga6c
riga7

Re: sed: individuare occorrenze multiple

Inviato: ven 26 nov 2010, 17:23
da targzeta
Non so se ti piace, ma questo (casino) dovrebbe fare la stessa cosa:

Codice: Seleziona tutto

sed -n 'h;:next n;/^ /{H;x;s/\n *//;$b end;x;b next;};x;p;x;:end ${p;q};h;b next' nomefile
Non capisco comunque perchè non ti piace la tua soluzione.

Emanuele