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 of last3 and last2 in my first solution (above).
  • declare sec"$count"="value" is a way to assign to sec1, sec2, sec3 and sec4 when count is 1, 2, 3 and 4.  It’s a little like eval, but safer.
  • The value, "${slice%%.*}", is analogous to the values my original answer assigns to first, second and third.

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)