sed: individuare occorrenze multiple

Se avete problemi con l'installazione e la configurazione di Slackware postate qui. Non usate questo forum per argomenti generali... per quelli usate Gnu/Linux in genere.

Moderatore: Staff

Regole del forum
1) Citare sempre la versione di Slackware usata, la versione del Kernel e magari anche la versione della libreria coinvolta. Questi dati aiutano le persone che possono rispondere.
2) Per evitare confusione prego inserire in questo forum solo topic che riguardano appunto Slackware, se l'argomento è generale usate il forum Gnu/Linux in genere.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

sed: individuare occorrenze multiple

Messaggio 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
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
umaga
Packager
Packager
Messaggi: 180
Iscritto il: lun 30 gen 2006, 10:19
Slackware: 13.37
Kernel: 2.6.38.4-smp
Desktop: KDE 4.7
Località: Cagliari

Re: sed: individuare occorrenze multiple

Messaggio 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

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: sed: individuare occorrenze multiple

Messaggio 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}}'
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6643
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: sed: individuare occorrenze multiple

Messaggio 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
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: sed: individuare occorrenze multiple

Messaggio 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
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6643
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: sed: individuare occorrenze multiple

Messaggio 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)
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: sed: individuare occorrenze multiple

Messaggio 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.
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6643
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: sed: individuare occorrenze multiple

Messaggio 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
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: sed: individuare occorrenze multiple

Messaggio 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.
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6643
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: sed: individuare occorrenze multiple

Messaggio 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
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: sed: individuare occorrenze multiple

Messaggio 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
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Mario Vanoni
Iper Master
Iper Master
Messaggi: 3174
Iscritto il: lun 3 set 2007, 21:20
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey
Località: Cuasso al Monte (VA)

Re: sed: individuare occorrenze multiple

Messaggio 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.

Avatar utente
ZeroUno
Staff
Staff
Messaggi: 5441
Iscritto il: ven 2 giu 2006, 14:52
Nome Cognome: Matteo Rossini
Slackware: current
Kernel: slack-current
Desktop: ktown-latest
Distribuzione: 01000000-current
Località: Roma / Castelli
Contatta:

Re: sed: individuare occorrenze multiple

Messaggio 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
Packages finder: slakfinder.org | Slackpkg+, per aggiungere repository a slackpkg

Codice: Seleziona tutto

1011010 1100101 1110010 1101111 - 0100000 - 1010101 1101110 1101111

Mario Vanoni
Iper Master
Iper Master
Messaggi: 3174
Iscritto il: lun 3 set 2007, 21:20
Nome Cognome: Mario Vanoni
Slackware: 12.2
Kernel: 3.0.4 statico
Desktop: fluxbox/seamonkey
Località: Cuasso al Monte (VA)

Re: sed: individuare occorrenze multiple

Messaggio 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

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6643
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: sed: individuare occorrenze multiple

Messaggio 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
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Rispondi