2016-03-08 19 views
5

Ho un file che contiene molte righe (il delimitatore di riga è ~). Ogni riga, ho molti elementi che sono separati da un delimitatore '*'. Quello che voglio fare è, Avrò una riga che inizia con stringa TRN nel mio file. Può contenere 4 (incluso TRN) o più punti dati. Qualcosa di simile,Come si può sostituire una parte di una linea con sed?

TRN*1*S521000035*1020494919~ 
TRN*1*S521000035*1020494919*787989800~ 

Desidero sostituire il quarto punto dati da questa linea a abc123. vale a dire,

TRN*1*S521000035*abc123~ 
TRN*1*S521000035*abc123*787989800~ 

Ho provato ad utilizzare il comando sed con espressioni regolari

sed -i 's/^TRN\*(.*)\*(.*)\*(.*)$/abc123/g' file.txt 

Ma l'intera stringa è sempre sostituito da abc123.

È possibile modificare solo il suo quarto punto di dati utilizzando il comando sed?

risposta

2

Utilizzando GNU sed:

$ sed -r -i 's/^((\w+\*){3})\w*(.*)/\1abc123\3/g' file.txt 

Uscita:

TRN*1*S521000035*abc123~ 
TRN*1*S521000035*abc123*787989800~ 
+0

Ha funzionato. Grazie mille! –

+0

Nel caso precedente volevo sostituire il quarto punto dati, solo se il primo punto dati è TRN. Così ho ottimizzato il comando come 'sed -r -i 's/^ (TRN \ *) ((\ w + \ *) {2}) \ w * (.*)/\ 1 \ 2abc123 \ 4/g '' –

2

sed è il tuo amico.

dare una prova di questa versione testata:

$ sed "s/^\(TRN[*][^*][^*]*[*][^*][^*]*[*]\)[^*][^*]*\(.*~\)/\1abc123\2/" afile.txt 
TRN*1*S521000035*abc123~ 
TRN*1*S521000035*abc123*787989800~ 

si potrebbe desiderare di leggere le pagine man per avere maggiori dettagli su regexp e sed

0

AWK dovrebbe fare il trucco in un modo piuttosto conciso e leggibile. FS cambia il separatore di campo in modo che tu possa identificare dove vuoi che si spezzi all'interno di una linea.

$ awk 'BEGIN { FS="*|~" }{ sub($4, "abc123"); print $0}' file.txt 

TRN*1*S521000035*abc123~ 
TRN*1*S521000035*abc123*787989800~ 
+0

Perché non usi' $ 4 = "abc123" '? Fare un sub invece è un po 'strano. –

+0

Perché quando l'ho fatto ha rimosso il "*" tra i campi e il "~" dalla fine della prima riga. Non so perché lo abbia fatto, ma ha risolto il problema. –

+0

Perché non hai impostato il separatore dei campi di uscita OFS. –

0

Mentre si può fare questo con sed è molto più facile per ottenere l'effetto desiderato con awk. Il programma awk è particolarmente utile per analizzare e trasformare i dati tabulari-strutturati, come nel tuo caso:

awk -F'*' -v OFS='*' '{$4 = "abc123"; print}' 

Questa legge:

awk   Run the program awk 
-F'*'  Use the * as a field delimiter on input 
-v OFS='*' Use the * as a field delimiter on output 
'{   On each record … 
    $4 = "abc123"; 
      … set the 4th field to "abc123" 
    print 
      … and print the curent record 
    }' 

E 'anche facile per espandere su questo esempio per selettivamente sostituire il 4 ° campo, in base al valore degli altri campi.

+1

Il comando 'awk' sta rimuovendo' ~ 'alla fine della riga 1 nell'esempio e questo comportamento non è voluto. – user3439894

+0

'awk 'BEGIN {ORS = RS =" ~ \ n "; FS = OFS =" * "} $ 4 =" abc123 "'' – 123

+1

@ 123, Il comando commento 'awk' introduce una nuova riga indesiderata dopo ogni riga esistente e l'ultima riga di "*** abc123 ~". – user3439894

1

Questo potrebbe funzionare per voi (GNU SED):

sed 's/[^*~]\+/abc123/4' file 

Sostituire la quarta occorrenza di qualcosa che è non contiene un ~ o un * con abc123.

Problemi correlati