sed: stampa solo il gruppo corrispondente


133

Voglio prendere gli ultimi due numeri (uno int, uno float; seguito da uno spazio bianco opzionale) e stamparli solo.

Esempio:

foo bar <foo> bla 1 2 3.4

Dovrebbe stampare:

2 3.4

Finora, ho il seguente:

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/replacement/p' 

mi darà

foo bar <foo> bla 1 replacement

Tuttavia, se provo a sostituirlo con il gruppo 1, viene stampata l'intera riga.

sed -n  's/\([0-9][0-9]*[\ \t][0-9.]*[\ \t]*$\)/\1/p' 

Come posso stampare solo la sezione della riga che corrisponde alla regex nel gruppo?

Risposte:


138

Abbina l'intera riga, quindi aggiungi .*a all'inizio della tua regex. Questo fa sì che l'intera riga venga sostituita con il contenuto del gruppo

echo "foo bar <foo> bla 1 2 3.4" |
 sed -n  's/.*\([0-9][0-9]*[\ \t][0-9.]*[ \t]*$\)/\1/p'
2 3.4

38
Ho dovuto aggiungere l' -ropzione o `--regexp-extended`, altrimenti stavo ottenendo invalid reference \1 on l'errore RHS` del comando s.
Daniel Sokolowski l'

15
@DanielSokolowski Penso che tu ottenga quell'errore se usi (e )invece di \(e \).
Daniel Darabos,

3
Ricorda anche di aggiungere .*alla fine del regexp se la stringa che vuoi estrarre non è sempre alla fine della riga.
Teemu Leisti,

3
Questo non funzionerà per me perché .*è avido e sed non ha un non avido.*?
sondra.kinsey

@DanielDarabos Basta menzionarlo (e )non genererà errori in Ubuntu 16.04. Quindi penso che questo commento sia obsoleto.
Li haonan,

72

grep è lo strumento giusto per l'estrazione.

usando il tuo esempio e il tuo regex:

kent$  echo 'foo bar <foo> bla 1 2 3.4'|grep -o '[0-9][0-9]*[\ \t][0-9.]*[\ \t]*$'
2 3.4

12
ottimo per l'intero gruppo, anche se sed è necessario per i singoli gruppi
jozxyqk,

grep -o non esegue il port su sistemi che eseguono msysgit ma sed lo fa.
cchamberlain,

Vedi la domanda collegata da @jozxyqk per una risposta che utilizza look-ahead e look-behind per risolverlo con grep.
Joachim Breitner,

È possibile estrarre un gruppo da un modello con grep -ochiamate inoltrate . stackoverflow.com/a/58314379/117471
Bruno Bronosky

12

E per l'ennesima opzione, andrei con awk!

echo "foo bar <foo> bla 1 2 3.4" | awk '{ print $(NF-1), $NF; }'

Questo dividerà l'input (sto usando STDIN qui, ma il tuo input potrebbe facilmente essere un file) su spazi, quindi stampa l'ultimo campo tranne uno, quindi l'ultimo campo. Le $NFvariabili contengono il numero di campi trovati dopo l'esplosione negli spazi.

Il vantaggio di ciò è che non importa se ciò che precede gli ultimi due campi cambia, a patto che tu voglia solo gli ultimi due continuerà a funzionare.


3

Il comando di taglio è progettato per questa situazione esatta. "Taglia" su qualsiasi delimitatore e quindi puoi specificare quali blocchi devono essere emessi.

Per esempio: echo "foo bar <foo> bla 1 2 3.4" | cut -d " " -f 6-7

Si tradurrà in output di: 2 3.4

-d imposta il delimitatore

-f seleziona l'intervallo di 'campi' da emettere, in questo caso sono i blocchi dal 6 ° al 7 ° della stringa originale. È inoltre possibile specificare l'intervallo come un elenco, ad esempio 6,7.


Per stampare solo alcune colonne, awk '{ print $2" "$6 }'
esegui il

@nurettin Penso che il tuo commento potrebbe essere stato pensato per una delle risposte awk.
carlin.scott,

Ho provato a tagliare quando ho visitato questa pagina e mi sono reso conto dei limiti e ho deciso di scrivere una versione più generalizzata in awk invece come commento per migliorare la qualità di questo post.
Nurettin,

1
Sì, penso che appartenga a una risposta diversa che coinvolge awk. Il comando cut per fare ciò che hai scritto è:cut -d " " -f 2,6
carlin.scott

ah, non lo sapevo, pensavo che potessi dare solo intervalli. Grazie per quello
Nurettin,

2

Sono d'accordo con @kent che questo è adatto per grep -o. Se devi estrarre un gruppo all'interno di un modello, puoi farlo con un 2 ° grep.

# To extract \1 from /xx([0-9]+)yy/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'xx[0-9]+yy' | grep -Eo '[0-9]+'
123
4

# To extract \1 from /a([0-9]+)b/
$ echo "aa678bb xx123yy xx4yy aa42 aa9bb" | grep -Eo 'a[0-9]+b' | grep -Eo '[0-9]+'
678
9
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.