Reputation: 55
I've got a file consisting of IPs and MAC address pairs and I need to pad the MAC addresses with zeros in each octet, but I don't want to change the IP. So this...
10.5.96.41 0:0:e:4c:b7:42
10.5.96.42 c4:f7:0:13:ef:32
10.5.96.43 0:e8:4c:60:2b:42
10.5.96.44 0:6a:bf:b:35:f1
Should get changed to this...
10.5.96.41 00:00:0e:4c:b7:42
10.5.96.42 c4:f7:00:13:ef:32
10.5.96.43 00:e8:4c:60:2b:42
10.5.96.44 00:6a:bf:0b:35:f1
I tried sed 's/\b\(\w\)\b/0\1/g'
but that produces:
10.05.96.41 00:00:0e:4c:b7:42
10.05.96.42 c4:f7:00:13:ef:32
10.05.96.43 00:e8:4c:60:2b:42
10.05.96.44 00:6a:bf:0b:35:f1
which is not desired because I only want to effect the MAC address portion.
Upvotes: 2
Views: 310
Reputation: 2855
very circuitous and verbose solution to deal with mawk
not having regex :: back-references
- the approach is to prepad every slot with extra zeros, then trim out the excess :
nawk ' sub(".+","\5:&:\3", $NF)^_ + gsub(":", "&00") + \ gsub("[0-9A-Fa-f]{2}:","\6&") + gsub("[^:]*\6|\5:|:00\3$",_)'
mawk ' sub("^", "\5:", $NF)^_ + gsub(":", "&00") + \ gsub("[^ :][^ :](:|$)", "\6&") + gsub("[^:]*\6|\5:",_)'
10.5.96.41 00:00:0e:4c:b7:42
10.5.96.42 c4:f7:00:13:ef:32
10.5.96.43 00:e8:4c:60:2b:42
10.5.96.44 00:6a:bf:0b:35:f1
To do it the proper gawk
gensub()
way
-- needed 2 calls to gensub()
- calling once ended up missing a few ::
gawk -be 'BEGIN { ___ *= __ = "([ :\t])([[:xdigit:]]?)(:|$)" _="\\10\\2\\3" } $___ = gensub(__, _, "g", gensub(__, _, "g"))'
Upvotes: 0
Reputation: 286
A succinct and precise solution for GNU sed:
sed -Ee 's/\b[0-9a-f](:|$)/0&/gi' file
(On macOS, I recommend installing gsed
using brew install gnu-sed
.)
Upvotes: 0
Reputation: 58473
This might work for you (GNU sed):
sed 's/\b.\(:\|$\)/0&/g' file
Prepend a 0
before any single character followed by a :
or the end of line.
Other seds may use:
sed 's/\<.\(:\|$\)/0&/g' file
Upvotes: 2
Reputation: 158080
With GNU sed:
sed -E ':a;s/([ :])(.)(:|$)/\10\2\3/g;ta' file
with any sed:
sed ':a;s/\([ :]\)\(.\):/\10\2:/g;ta' file
Explanation (of the GNU version)
:a # a label called 'a', used as a jump target
; # command separator
s # substitute command ...
/([ :])(.)(:|$)/ # search for any single char which is enclosed by
# either two colons, a whitespace and a colon or
# a colon and the end of the line ($)
# Content between () will be matched in a group
# which is used in the replacement pattern
\10\2\3 # replacement pattern: group1 \1, a zero, group2 and
# group3 (see above)
/g # replace as often as possible
; # command separator
ta # jump back to a if the previous s command replaced
# something (see below)
The loop using the label a
and the ta
command is needed because sed won't match a pattern again if input was already part of a replacement. This would happen in this case for example (first line):
0:0
When the above pattern is applied, sed would replace
<space>0: by <space>00: <- colon
The same colon would not match again as the beginning : of the second zero. Therefore the loop until everything is replaced.
Upvotes: 0
Reputation: 203985
With any sed that uses -E
to support EREs, e.g. GNU sed or OSX/BSD (MacOS) sed:
$ sed -E 's/[ :]/&0/g; s/0([^:]{2}(:|$))/\1/g' file
10.5.96.41 00:00:0e:4c:b7:42
10.5.96.42 c4:f7:00:13:ef:32
10.5.96.43 00:e8:4c:60:2b:42
10.5.96.44 00:6a:bf:0b:35:f1
and with any sed:
$ sed 's/[ :]/&0/g; s/0\([^:][^:]:\)/\1/g; s/0\([^:][^:]$\)/\1/' file
10.5.96.41 00:00:0e:4c:b7:42
10.5.96.42 c4:f7:00:13:ef:32
10.5.96.43 00:e8:4c:60:2b:42
10.5.96.44 00:6a:bf:0b:35:f1
Upvotes: 2
Reputation: 23677
Since you've tagged macos
, I'm not sure if this will work for you. I tested it on GNU awk
$ awk '{gsub(/\<[0-9a-f]\>/, "0&", $2)} 1' ip.txt
10.5.96.41 00:00:0e:4c:b7:42
10.5.96.42 c4:f7:00:13:ef:32
10.5.96.43 00:e8:4c:60:2b:42
10.5.96.44 00:6a:bf:0b:35:f1
awk
is good for field processing, here you can simply perform substitution only for second field
But, I see \b
and \w
with your sed
command, so you are using GNU sed
? If so,
sed -E ':a s/( .*)(\b\w\b)/\10\2/; ta' ip.txt
With perl
$ perl -lane '$F[1] =~ s/\b\w\b/0$&/g; print join " ", @F' ip.txt
10.5.96.41 00:00:0e:4c:b7:42
10.5.96.42 c4:f7:00:13:ef:32
10.5.96.43 00:e8:4c:60:2b:42
10.5.96.44 00:6a:bf:0b:35:f1
If you want to get adventurous, specify that you want to avoid replacing first field:
perl -pe 's/^\H+(*SKIP)(*F)|\b\w\b/0$&/g' ip.txt
Upvotes: 4