Awk,sed : change every 2nd field ":" to "|"

Hi Experts,
I have a string with colon delimited, want 2nd colon to be changed to a pipe.

data:
101:8:43:4:72:14:41:69:85:3:137:4:3:0:4:0:9:3:0:3:12:3:

I am trying with sed, but can change only 1 occurance:

echo "101:8:43:4:72:14:41:69:85:3:137:4:3:0:4:0:9:3:0:3:12:3:" | sed 's/:/|/2'
101:8|43:4:72:14:41:69:85:3:137:4:3:0:4:0:9:3:0:3:12:3:

Want this for every 2nd ":" occurance to be changed to "|"

The desired output should be:

101:8|43:4|72:14|41:69|85:3|137:4|3:0|4:0|9:3|0:3|12:3|

Thanks,

---------- Post updated at 08:05 PM ---------- Previous update was at 07:42 PM ----------

I got it now with sed :

  1. made a script file for sed.
cat script
s/:/|/2
s/:/|/3
s/:/|/4
s/:/|/5
s/:/|/6
s/:/|/7
s/:/|/8
s/:/|/9
s/:/|/10
s/:/|/11
s/:/|/12
  1. executed the script: Got desired output.
$ awk -f script data
101:8|43:4|72:14|41:69|85:3|137:4|3:0|4:0|9:3|0:3|12:3|

In case you are interested in a more compact solution which does not depend on the number of fields:

sed 's/\([^:]*:[^:]*\):/\1|/g'

Regards,
Alister

1 Like

A different type of Perl alternative (if you are interested):

perl -lpe '@a = split /(:)/, $_, -1; @a = map { ($_+1)%4 ? $a[$_] : "|" } 0..$#a if @a>3;
$_ = join("",@a)' file

This could be easily done with one regex substitution. But, the above solution is just for fun/amusement.

1 Like

It could be shortened / simplified further a little:

sed 's/\(:[^:]*\):/\1|/g' file

or

perl -pe 's/(:.*?):/$1|/g' file
1 Like

Alister ,
Thanks I checked the sed code works great.

sed 's/\([^:]*:[^:]*\):/\1|/g' file

Thanks,

Scrutinizer,
This code also works great, thanks a lot for the small code,

sed 's/\(:[^:]*\):/\1|/g' file

Could you guys please explain how the substitue portion working here:
(2nd ":" to "|" )

sed 's/\(:[^:]*\):/\1|/g'

I can understand that

 \1|/

is changing the first search pattern to "|" , but the regex code is little complicated seems.

---------- Post updated at 12:28 AM ---------- Previous update was at 12:18 AM ----------

Thanks to elixir_sinari , for the perl code, worked. but looks like much more complicated. : (

The sed command uses a substitute command ( s/.../... / ) . The first part of the expression contains a basic regular expression (regex). The escaped parentheses \( and \) are used to group parts of matched text that can be back referenced by \1 in the second part of the s-command.

So in this case only the second colon is outside the grouped part and does not get back referenced, so effectively it gets discarded. If we apply this to your input file then the first match is :8: , which gets substituted with :8| . At the end of the expression is the letter g , which is the "global" flag, which means that the operation should be repeated for every occurrence on the line.

So this will be repeated, and crucial here, is that the next match will start after the previous match, so next up will be :4: which becomes :4| and then :14: becomes :14| and so on...