Mostly for the fun of it, in the zsh shell, to do it on a variable, using its string manipulation operators:
$ hex=0x100070b7e4323096 $ set -o extendedglob $ echo ${${hex//(#m)??/:$MATCH}[5,-1]} 10:00:70:b7:e4:32:30:96
Where we replace every two characters ?? (with (#m) activating the capturing of the match in $MATCH), with : and the match, using the Korn-style ${param//pattern/replacement} operator, and then select the 5th to last (-1) characters from the result. Essentially the same as sed's s/../:&/g; s/....//.
$ printf "${(r[5*8-1][%s%s:])}\n" ${(s[])hex#0x} 10:00:70:b7:e4:32:30:96
Where ${hex#0x} is the Korn/POSIX operator to strip a leading 0x, the s[] parameter expansion flag splits the result into the character constituents which we pass as separate arguments to printf.
The format argument for printf is %s%s:%s%s:%s%s:%s%s:%s%s:%s%s:%s%s:%s%s\n which we obtain using the r[length][pad] right padding parameter expansion flag applied to no parameter, here using %s%s: as the pad and 5*8-1 as the length so as to have 8 of them without the last :.
Or using csh-style modifiers:
$ set -o histsubstpattern -o extendedglob $ echo $hex:s/0x//:fs/(#m)[^:](#c4)/$MATCH[1,2]:$MATCH[3,4] 10:00:70:b7:e4:32:30:96
Where we remove the 0x, then look for 4 non-: characters, insert a : in the middle, and repeat the process until there's no more change (the f prefix to the s modifier). Essentially like GNU sed's echo $hex | sed -E 's/0x//;:1;s/([^:][^:])([^:][^:])/\1:\2/;t1' or echo $hex | perl -lpe 's/0x//; while (s/([^:][^:])([^:][^:])/$1:$2/){}'
Or a translation of @Raffa's approach into zsh, using regexps (extended or PCRE if the rematchpcre option is enabled):
$ [[ $hex =~ ${hex//??/(..)} ]]; echo ${(j[:])match[2,-1]} 10:00:70:b7:e4:32:30:96
Or globs:
$ set -o extendedglob $ [[ $hex = (#b)${~hex//??/(??)} ]]; echo ${(j[:])match[2,-1]} 10:00:70:b7:e4:32:30:96
Or the lame (but certainly easier to follow) approach:
$ echo $hex[3,4]:$hex[5,6]:$hex[7,8]:$hex[9,10]:$hex[11,12]:$hex[13,14]:$hex[15,16]:$hex[17,18] 10:00:70:b7:e4:32:30:96
Or the ksh93-style equivalent (also supported by bash, though you'd need to double-quote it in those shells):
$ echo ${hex:2:2}:${hex:4:2}:${hex:6:2}:${hex:8:2}:${hex:10:2}:${hex:12:2}:${hex:14:2}:${hex:16:2} 10:00:70:b7:e4:32:30:96
You could pass that list of offsets as arguments to an anonymous function:
$ set -o extendedglob $ (){echo ${(j[:])@/(#m)*/${hex:$MATCH:2}}} {2..16..2} 10:00:70:b7:e4:32:30:96
Where ${array/(#m)*/something-with-$MATCH} is a common way to do something similar to the map() of perl or other languages, the j[:] parameter expansion flag to join.
More fun ways:
$ echo $hex | grep -Eo '[[:xdigit:]]{2}' | paste -sd : - 10:00:70:b7:e4:32:30:96
Abusing hexdump:
$ echo $hex | hexdump -e '/2 "%.0s" 7/2 "%.2s:" /2 "%s" /9 "%.0s"' 10:00:70:b7:e4:32:30:96
The natural way with perl:
$ echo $hex | perl -lne 'print join ":", s/^0x//r =~ /../g' 10:00:70:b7:e4:32:30:96