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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With