Reputation: 798
I am trying to figure out how to do the following with sed:
I got a list of IPv4 addresses and I am trying to make them all uniform in the display. So for example: 1.2.4.32
would be 001.002.004.032
. 10.125.62.1
would be 010.125.062.001
.
I am trying to use sed to do it because that's what I am learning right now.
I got these two, which will take any one or two digit number and append zeros at the front.
sed 's/\<[0-9][0-9]\>/0&/g' file
sed 's/\<[0-9]\>/00&/g' file
But that runs into a more practical problem in that my input file will have single or double digits numbers in other non-IP address places. Example:
host-1 1.2.3.32
So I need a way for it to look for the full IP address, which I thought could be achieved by this
sed 's/\.\<[0-9]\>/00&/g'
but not only does that ignore the case of 1.something.something.something
, but also it appends the 00
at the end of 3rd octet for some reason.
echo "10.10.88.5" | sed 's/\.\<[0-9]\>/00&/g'
10.10.8800.5
Sample file:
Jumpstart Server jumo 10.20.5.126
Jumpstart Server acob 10.20.5.168
NW1 H17 Node cluster 10.10.161.87
NW1 H17 Node-1 10.10.161.8
NW1 H17 Node-2 10.10.161.9
ts-nw1 10.10.8.6
Upvotes: 10
Views: 561
Reputation: 21965
$ cat 37222835.txt
Jumpstart Server jumo 10.20.5.126 10.29.23.24
Jumpstart Server acob 10.20.5.168 dig opt
Jumpstart Server reac 251.218.212.1 rel
NW1 H17 Node cluster 10.10.161.87
NW1 H17 Node-1 10.10.161.8
NW1 H17 Node-2 10.10.161.9
ts-nw1 10.10.8.6
Nw2 HW12 Node-3 192.168.0.1
cluster
Doing :
sed -n 's/\([1]\?[0-9][0-9]\?\|2[0-4][0-9]\|25[0-5]\)\{1\}\.'\
'\([1]\?[0-9][0-9]\?\|2[0-4][0-9]\|25[0-5]\)\{1\}\.'\
'\([1]\?[0-9][0-9]\?\|2[0-4][0-9]\|25[0-5]\)\{1\}\.'\
'\([1]\?[0-9][0-9]\?\|2[0-4][0-9]\|25[0-5] \)/00\1\.00\2\.00\3\.00\4/g;
s/0\+\([0-9]\{3\}\)/\1/g;p' 37222835.txt
gives :
Jumpstart Server jumo 010.020.005.126 010.029.023.024
Jumpstart Server acob 010.020.005.168 dig opt
Jumpstart Server reac 251.218.212.001 rel
NW1 H17 Node cluster 010.010.161.087
NW1 H17 Node-1 010.010.161.008
NW1 H17 Node-2 010.010.161.009
ts-nw1 010.010.008.006
Nw2 HW12 Node-3 192.168.000.001
cluster
Advantage over the approach mentioned by @benjamin-w
This can replace multiple ip addresses in the same line
Disadvantage(the approach mentioned by @benjamin-w remedy this)
Had there be a word say Node-000234
it would be changed to Node-234
. In fact, you could work on the second substitution command to get the desired behaviour.
Upvotes: 3
Reputation: 52122
The idiomatic way of changing only parts of a line is to copy it to the hold space, remove the parts we're not interested in from the pattern space, get the hold space back and then rearrange the pattern space to replace the part we've changed with our new version.
This should work (replace -r
with -E
for BSD sed):
sed -r 'h # Copy pattern space to hold space
# Remove everything except IP address from pattern space
s/.*\b(([0-9]{1,3}\.){3}[0-9]{1,3})\b.*/\1/
s/([0-9])+/00&/g # Prepend '00' to each group of digits
s/[0-9]*([0-9]{3})/\1/g # Only retain last three digits of each group
G # Append hold space to pattern space
# Replace old IP with new IP
s/(.*)\n(.*)\b([0-9]{1,3}\.){3}[0-9]{1,3}\b(.*)/\2\1\4/' infile
The last step is the most complicated one. Just before it, a line looks like this (newline as \n
, end of line as $
):
010.020.005.126\nJumpstart Server jumo 10.20.5.126$
i.e., our new and improved IP address, a newline, then the complete old line. We now capture the underlined groups:
010.020.005.126\nJumpstart Server jumo 10.20.5.126$
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
(.*) \n (.*) \b...\b (.*)
\1 \2 \3 \4
and rearrange the line by using group 2, then groups 1 (our new IP) and 4. Notice that
\2\1\4
in the substitution (there are no non-capturing groups in sed).The overall output is
Jumpstart Server jumo 010.020.005.126
Jumpstart Server acob 010.020.005.168
NW1 H17 Node cluster 010.010.161.087
NW1 H17 Node-1 010.010.161.008
NW1 H17 Node-2 010.010.161.009
ts-nw1 010.010.008.006
The same as a solidly unreadable one-liner:
sed -r 'h;s/.*\b(([0-9]{1,3}\.){3}[0-9]{1,3})\b.*/\1/;s/([0-9])+/00&/g;s/[0-9]*([0-9]{3})/\1/g;G;s/(.*)\n(.*)\b([0-9]{1,3}\.){3}[0-9]{1,3}\b(.*)/\2\1\4/' infile
\b
is a GNU extension. The script mostly works without it as well; using it makes sure that blah1.2.3.4blah
is left alone.
Upvotes: 5