Home > Back-end >  How to substitute a substring delimited by separator in a specific position with sed [duplicate]
How to substitute a substring delimited by separator in a specific position with sed [duplicate]

Time:09-16

I have a record like this:

aaa|11|bcvdgsf|11|eyetwrt|11|kkjdksjk

I would substitute the second occurrence of "11" with nother substring, for example XX. So the output would be

aaa|11|bcvdgsf|XX|eyetwrt|11|kkjdksjk

I tryed to use this command:

#echo "z|11|a|11|b|11|" | sed 's/\(|11\{2\}\)/\|XX/'

but record does not change

CodePudding user response:

You could use this to say "replace the second instance of 11 delimited by word boundaries on both sides with XX:"

$ sed 's/\b11\b/XX/2' <<< 'aaa|11|bcvdgsf|11|eyetwrt|11|kkjdksjk'
aaa|11|bcvdgsf|XX|eyetwrt|11|kkjdksjk

This requires GNU sed for \b support.

CodePudding user response:

If only whole field has to be matched:

$ cat ip.txt
z|11|a|11|b|11|
aaa|11|bcvdgsf|11|eyetwrt|11|kkjdksjk
11|11.2|abc|11|cca
11||11
11|11|ac
a|11|asd|11

$ awk 'BEGIN{FS=OFS="|"}
       {c=0; for(i=1; i<=NF; i  ) if($i=="11" &&   c==2) $i="XX"}
       1' ip.txt
z|11|a|XX|b|11|
aaa|11|bcvdgsf|XX|eyetwrt|11|kkjdksjk
11|11.2|abc|XX|cca
11||XX
11|XX|ac
a|11|asd|XX
  • FS=OFS="|" use | as input and output field separator
  • c=0 initialize counter for every line
  • for(i=1; i<=NF; i ) to loop over all input fields
  • $i=="11" && c==2 if field content is exactly 11, increment counter and check if it is the second match
  • $i="XX" change field content as needed
  • 1 idiomatic way to print $0

Similar logic with perl using lookarounds to match field boundary:

perl -lpe '$c=0; s/(?<![^|])11(?![^|])/  $c==2 ? "XX" : $&/ge'

CodePudding user response:

Please try my (working) solution:

echo "z|11|a|11|b|11|" | sed -r 's/^([a-z] \|11\|[a-z] \|)(11)(. )$/\1XX\3/'
  • Related