possiamo stampare l'ultima parola di ogni riga in linux usando il comando sed?


9

supponiamo, se esiste un file costituito dalle seguenti righe, se lo sono

12345 567 7878 66

   er3 t45t y6y46y 


 4y6 y656y y5y

   46y6 65y7 y66uyuy

 yy46y6y

L'output deve essere simile a:

66

y6y46y

y5y

y66uyuyy

y46y6y

Ho provato il sed 's/.* //g'nome file del comando e molti altri sedcomandi, ma non funziona.

Posso sapere qual è il sedcomando esatto ?


È un must da usare sed?
coffeMug

Risposte:


8
awk '{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//'

Ciò stamperebbe comunque una riga vuota per ogni riga vuota. Per evitarlo:

awk 'NF{print $NF}'
sed 's/[[:blank:]]*$//;s/.*[[:blank:]]//;/./!d'

Singolo alternativa espressione: sed -n 's/.*[[:blank:]]\+\([^[:blank:]]\+\)[[:blank:]]*$/\1/p'.
Jimmij,

@jimmij - che non funziona se l'ultima sequenza non vuota è anche la prima e non ci sono spazi che la precedono. Inoltre, potresti anche semplicemente fare .*alla coda, probabilmente: escludere qualsiasi cosa tranne gli spazi vuoti finali comunque con .*[^[:blank:]].
Mikeserv,


4

Puoi provare :

  • sed 's/.* //'
  • awk '{print $NF}'

4

Ci sei quasi. Basta specificare l'ultima parola:

sed 's/^.* \([^ ][^ ]*\)/\1/g'

Cosa fa:

  1. '^. *' elimina tutto all'inizio della riga e tutti gli spazi.
  2. '\ (...) \' corrisponde a un modello e lo restituisce come \ 1.
  3. '[^]' corrisponde a tutto senza uno spazio al suo interno.

(Modificato per aggiungere una soluzione migliore. Grazie Hildred!)


1
Ecco un'espressione più breve: sed -r 's/.* ([^ ]+)/\1/g'se sono consentite espressioni regolari estese, di solito è il caso.
MKalkov,

Versione più breve, utilizzando la sostituzione di ciò che non si desidera conservare piuttosto che ciò che si desidera conservare:sed 's/.* //'
Uriel

2

È possibile utilizzare un modello adeguato grepinvece di sed, ad esempio:

grep -o "[a-Z0-9]*$"

In questo esempio, [...]contiene intervalli di caratteri considerati appropriati per una "parola" (alfanumerici in questo caso, è possibile aggiungere altri simboli, alcuni dei quali devono essere salvati).


2
Ciò presuppone che non ci sia spazio vuoto alla fine della riga. a-Zpoiché un intervallo non ha molto senso, anche in locali basati su ASCII. Nota che -oè un'estensione GNU.
Stéphane Chazelas,

0

Se qualifichi una parola per indicare una sequenza di 1 o più caratteri non vuoti, la risposta è sicuramente sì, ed è anche molto semplice. Questo perché [[:blank:]]*e [^[:blank:]]*sono complementi booleani e - purché tutti i caratteri in una stringa siano completi - [[:blank:]]*U [^[:blank:]]*può descrivere qualsiasi stringa possibile allo stesso modo .*.

Se all'interno di una stringa esiste un carattere incompleto o una sequenza di byte altrimenti non valida, nessuno dei due può descriverlo con esattezza, come talvolta accade quando si interpreta una stringa con una codifica errata. Per garantire un carattere completo per byte in qualsiasi stringa, la locale C può essere forzata come:

LC_ALL=C sed ...

... che eviterebbe qualsiasi problema che descriva la corda dalla testa alla coda con un modello tutto compreso come .*o([ ]*[^ ]*)*

Un modello completamente complementare può ripetere tutte le volte che è necessario da sinistra a destra la lunghezza di qualsiasi stringa per atterrare sull'ultima occorrenza possibile senza alcuna interruzione nel modello. Questo è, in definitiva, un linguaggio regolare.

BRE:

sed 's/\(\([^[:blank:]]*\)[[:blank:]]*\)*/\2/'

ERE:

sed -E 's/(([^[:blank:]]*)[[:blank:]]*)*/\2/'

Entrambe queste versioni stamperanno comunque righe vuote, e questo perché la *stella di Kleene corrisponde a zero o più occorrenze di un motivo. Prima corrisponde a zero o più caratteri non vuoti, quindi zero o più caratteri vuoti, quindi zero o più occorrenze delle corrispondenze raggruppate fino a quando non corrisponde alla stringa nella sua interezza.

Avendo abbinato tutto questo, la magia accade nella sostituzione: i riferimenti restituiti dai gruppi \1e \2sono le ultime occorrenze di ciascuno. Pertanto, quando viene effettuata la sostituzione, tutta la stringa viene sostituita con solo l'ultima occorrenza su una riga di zero o più caratteri non vuoti o sul sottogruppo \2.

Ovviamente questo funziona per ogni possibile stringa, anche vuota, il che significa che entrambi i moduli stamperanno i caratteri di nuova riga per le righe che contengono solo caratteri vuoti o nessuno. Per gestirlo ci sono un paio di cose che puoi fare, ma prima rendiamo la classe di caratteri un po 'più facile da scrivere:

b='[:blank:]'

Ora, per stampare solo se una riga contiene uno o più caratteri non vuoti puoi fare:

BRE:

sed -n "s/\(\([^$b]*\)[$b]*\)*/\2/;/./p"

ERE:

sed -En "/[^$b]/s/(([^$b]*)[$b]*)*/\2/p"
  1. Caso BRE: la sostituzione viene sempre eseguita e vengono stampati solo gli spazi modello con almeno un carattere rimanente.
  2. Caso ERE: la sostituzione viene sempre e solo tentata su uno spazio modello contenente almeno un carattere non vuoto.

Entrambe le forme funzioneranno con entrambi i metodi, purché la sintassi sia corretta.

L' opzione -ndisabilita la stampa automatica dello spazio del motivo e il pflag sui comandi s///ubstitution o /address /stampa i suoi risultati solo in caso di successo.

Questa stessa logica può essere applicata per ottenere qualsiasi {num}occorrenza, come ad esempio:

BRE:

sed -n "s/\([$b]*\([^$b]\{1,\}\)\)\{num\}.*/\2/p"

ERE:

sed -En "s/([$b]*([^$b]+)){num}.*/\2/p"

... in cui numentrambe le regexps possono essere sostituite con un numero per stampare solo la {num}ricorrenza specificata di una sequenza di caratteri non vuoti. Qui viene utilizzata una forma leggermente diversa per garantire che il conteggio non sia distorto per lo spazio iniziale in una stringa.

Si noti che il -Epassaggio ERE su sedè supportato nelle versioni BSD e GNU, sebbene non sia ancora una sintassi standard POSIX.


Belle spiegazioni, bel trucco, ma nota che non funzionerà con le sed implementazioni tradizionali (come Solaris / usr / bin / sed) e sarà più costoso dell'approccio più semplice (esaurisce la memoria con righe di input lunghe più di 25 caratteri con il sed_su3dal toolchest Heirloom per esempio). Quindi, anche se mi piace la risposta, non consiglierei questo approccio.
Stéphane Chazelas,

Non sembra funzionare neanche in FreeBSD.
Stéphane Chazelas,

@ StéphaneChazelas - sì, la performance è davvero terribile per una cosa del genere, ma può essere molto efficace per individuare eventi numerati. E per un caso di fine linea s/.* \([^[:blank:]]\{1,\}\).*/\1/è molto meglio, ma è più difficile quando sono coinvolte più linee. Solo l'altro giorno, però, ho scoperto che 's/\(\n\)*/\1/g;s/\n\(\n.*\)*/&&/[num];s///[samenum]è abbastanza efficace. Ad ogni modo, fintanto che non c'è un errore evidente nella logica, allora sono felice - ho solo pensato che avrei dovuto perdere qualcosa.
Mikeserv,

@ StéphaneChazelas - oh, e riguardo alle seds più vecchie - è un po 'strano - dovrebbe essere il suono secondo lo standard. xrat afferma ... Gli sviluppatori standard consideravano il comportamento storico comune, che supportava "\n*", ma non "\n\{min,max\}", "\(...\)*", o "\(...\)\{min,max\}", come risultato non intenzionale di un'implementazione specifica, e supportavano sia la duplicazione che le espressioni di intervallo a seguito di sottoespressioni e riferimenti secondari.
Mikeserv,

@ StéphaneChazelas - E lo standard dice ... Se la sottoespressione a cui fa riferimento il riferimento a ritroso corrisponde a più di una stringa a causa di un asterisco ( '*' )o di un'espressione di intervallo (vedi punto (5)), il riferimento a ritroso deve corrispondere all'ultimo (all'estrema destra ) di queste stringhe. Sono abbastanza sicuro di averlo provato minisedcomunque - sicuramente stavo testando qualcosa di strano con minisedl'altro giorno, comunque.
Mikeserv,

-1

Sì. Il seguente comando sed rimuove prima tutti gli spazi bianchi finali ( s/ *$//) e poi tutto fino all'ultimo spazio bianco incluso ( s/.* //). Probabilmente vale la pena sostituire lo spazio bianco letterale con [[:blank:]]al fine di catturare schede e altri personaggi simili allo spazio.

$ echo "  aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc   " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "aaa bbb cc" | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "  cc  " | sed -e 's/ *$//' -e 's/.* //'
cc
$ echo "cc" | sed -e 's/ *$//' -e 's/.* //'
cc

-1
cat file_name | rev | cut -f1 -d ' ' | rev
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.