replacing a string contained withing two strings with an incremental counter in bash

Viewed 92

I am trying to change a file looking like this :

>sample_A#Dakota
text
text
text
>text_2#Idao
text
text
text
>junk_1#Alabama
text
text
text
>example_4#Dakota
text
text
text
>example5#Honduras
text
text
text

to a file looking like this :

>model_1#Dakota
text
text
text
>model_2#Idao
text
text
text
>model_3#Alabama
text
text
text
>model_4#Dakota
text
text
text
>model_5#Honduras
text
text
text

So, I need to find the text between > and #, and replace it with "model" followed by an incremental number. I have found some answers only for doing these thing separately, but I haven't been able to combine them. I would want to use bash, with a one-line answer like a sed or an awk. I have tried this :

awk 'BEGIN { cntr = 0 } />/,/#/ { cntr++ ; print "model", cntr } !/>/,/#/ { print $0 }' infile

but I got this :

model 1
text
text
text
model 2
>text_2#Idao
text
text
text
model 3
>junk_1#Alabama
text
text
text
model 4
>example_4#Dakota
text
text
text
model 5
>example5#Honduras
text
text
text

Thanks in advance, T

5 Answers
$ awk '/^>.*#/{sub(/^>[^#]+/, ">model_" ++c)} 1' ip.txt
>model_1#Dakota
text
text
text
>model_2#Idao
text
text
text
>model_3#Alabama
text
text
text
>model_4#Dakota
text
text
text
>model_5#Honduras
text
text
text
  • /^>.*#/ if line starts with > and has # in the line
  • sub function helps to search and replace first match
  • /^>[^#]+/ match characters from start of line from > until just before # character
  • ">model_" ++c replacement string
    • c will be zero at the start (since this is numerical context), ++c will give the value after incrementing, so first time we get 1, next time 2 and so on
$ awk 'sub(/^>[^#]+/,""){$0=">model1_" (++cnt) $0} 1' file
>model1_1#Dakota
text
text
text
>model1_2#Idao
text
text
text
>model1_3#Alabama
text
text
text
>model1_4#Dakota
text
text
text
>model1_5#Honduras
text
text
text

Could you please try following too.

awk 'match($0,/>.*#/){print ">model_"++count"#" substr($0,RSTART+RLENGTH);next} 1' Input_file
awk '/^>/{$0=">model_" ++c "#" $3}1' FS='[>#]' file

I used > and # as field separators.

Output:

>model_1#Dakota
text
text
text
>model_2#Idao
text
text
text
>model_3#Alabama
text
text
text
>model_4#Dakota
text
text
text
>model_5#Honduras
text
text
text

This might work for you (GNU sed and shell):

sed -E '/^>.*#/{x;s/.*/expr & + 1/e;x;G;s/^[^#]*(.*)\n(.*)/echo "model_\2\1"/e}' file

For lines that begin > and contain #, increment a counter in the hold space (HS), append the HS to the current line and re-arrange into the desired format.

Related