1

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

oguz ismail
  • 1
  • 16
  • 47
  • 69
  • https://www.google.com/search?q=sed+replac+second+occurence+in+line -> https://www.geeksforgeeks.org/sed-command-in-linux-unix-with-examples/ -> `Replacing the nth occurrence of a pattern in a line` -> `sed 's/11/XX/2'`. Learn regexes with https://regexcrossword.com/ . – KamilCuk Sep 15 '21 at 12:59

3 Answers3

1

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.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
  • Thanks. It works. I was thinking about how tell to 'sed' to switch position by '|' delimeter, but '\b' i see that do this by itself. I have to deepen into '-b' option. Thanks – Alessandro Barca Sep 15 '21 at 13:45
  • @AlessandroBarca `\b` will change even if a field contains data like `11.2` or `(11)`. – Sundeep Sep 15 '21 at 13:56
1

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'
Sundeep
  • 23,246
  • 2
  • 28
  • 103
0

Please try my (working) solution:

echo "z|11|a|11|b|11|" | sed -r 's/^([a-z]+\|11\|[a-z]+\|)(11)(.+)$/\1XX\3/'
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74