Bash: Extract one of the four sections of an IPv4 address
Assuming the default value of IFS you extract each octet into it's own variable with:
read A B C D <<<"${IP//./ }"
Or into an array with:
A=(${IP//./ })
Your problem statement may be a bit more liberal than you intended. At the risk of exploiting a loophole, here’s the solution muru alluded to:
first=${IP%%.*}
last3=${IP#*.}
second=${last3%%.*}
last2=${last3#*.}
third=${last2%.*}
fourth=${last2#*.}
echo "$IP -> $first, $second, $third, $fourth"
This is somewhat clunky. It defines two throw-away variables, and it is not readily adapted to handle more sections (e.g., for a MAC or IPv6 address). Sergiy Kolodyazhnyy’s answer inspired me to generalize the above to this:
slice="$IP"
count=1
while [ "$count" -le 4 ]
do
declare sec"$count"="${slice%%.*}"
slice="${slice#*.}"
count=$((count+1))
done
This sets sec1
, sec2
, sec3
and sec4
, which can be verified with
printf 'Section 1: %s\n' "$sec1"
printf 'Section 2: %s\n' "$sec2"
printf 'Section 3: %s\n' "$sec3"
printf 'Section 4: %s\n' "$sec4"
- The
while
loop should be easy to understand — it iterates four times. - Sergiy chose
slice
as the name for a variable that takes the place oflast3
andlast2
in my first solution (above). declare sec"$count"="value"
is a way to assign tosec1
,sec2
,sec3
andsec4
whencount
is1
,2
,3
and4
. It’s a little likeeval
, but safer.- The
value
,"${slice%%.*}"
, is analogous to the values my original answer assigns tofirst
,second
andthird
.
I do realize that you specifically asked for a solution that DID NOT temporarily redefine IFS
, but I have a sweet and simple solution that you didn't cover, so here goes:
IFS=. ; set -- $IP
That short command will put the elements of your IP address in the shell's positional parameters $1
, $2
, $3
, $4
. However, you'll probably want to first save the original IFS
and restore it afterwards.
Who knows? Maybe you'll reconsider and accept this answer for its brevity and efficiency.
(This was previously incorrectly given as IFS=. set -- $IP
)