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 separatorc=0
initialize counter for every linefor(i=1; i<=NF; i )
to loop over all input fields$i=="11" && c==2
if field content is exactly11
, increment counter and check if it is the second match$i="XX"
change field content as needed1
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/'