Converting MAC Address Formats with macfmt

MAC addresses are written in an astonishingly big number of slightly different ways. As long as they are intended for human consumption, that is OK. But if they are used to match on program output, e.g to check the ARP table of a router, the correct format for that router model has to be used. Manual conversion is easy, but nevertheless error-prone. Thus I have written a small AWK script called macfmt to convert from and to the MAC address formats I know.

Usage

macfmt [-v cap=CASE] [-v format=FORMAT]
  CASE   is one of: lower, upper
  FORMAT is one of: all, cisco, linux, enterasys, cabletron, broadcom, vmps, netsight, hp, hex, hexprefix, pxe, pgsql, hexpostfix, arista, exos

Examples

$ echo 01:23:45:67:89:ab | macfmt
0123.4567.89ab 01:23:45:67:89:ab 01-23-45-67-89-AB 01:23:45:67:89:AB 0123:4567:89AB 0123.4567.89AB 01.23.45.67.89.AB 012345-6789ab 0123456789ab 0x0123456789ab 01 23 45 67 89 AB 012345:6789ab 0123456789ABh
$ echo 01-23-45-67-89-AB | macfmt -v format=linux
01:23:45:67:89:ab
$ echo 0123:4567:89AB | macfmt -v format=cisco
0123.4567.89ab
$ echo 0123.4567.89ab | macfmt -v format=linux -v cap=upper
01:23:45:67:89:AB

Compatibility

I have developed macfmt on Solaris 10 using its new AWK (/usr/xpg4/bin/awk). It works as well with Gawk, the GNU Project's AWK implementation. I have intended macfmt to work with any POSIX compatible AWK, help in improving compatibility is welcome.

macfmt does not work with mawk versions below 1.3.4, because those did not support character classes in regular expressions. This might be a problem for some Ubuntu users, because mawk is the default AWK interpreter there. To fix this, install gawk on Ubuntu and change the first line of the script to:

#! /usr/bin/gawk -f

Gawk One-Liners

Gawk supports defining fields by content using FPAT. This enables one-line Gawk programs for MAC address formatting, one for each of the different output formats:

Cisco (or Arista)
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print tolower($1 $2 "." $3 $4 "." $5 $6)}'
Linux (or ExtremeXOS)
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print tolower($1 ":" $2 ":" $3 ":" $4 ":" $5 ":" $6)}'
Enterasys
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 "-" $2 "-" $3 "-" $4 "-" $5 "-" $6)}'
Cabletron
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 ":" $2 ":" $3 ":" $4 ":" $5 ":" $6)}'
Broadcom
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 $2 ":" $3 $4 ":" $5 $6)}'
VMPS
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 $2 "." $3 $4 "." $5 $6)}'
NetSight
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 "." $2 "." $3 "." $4 "." $5 "." $6)}'
HP
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print tolower($1 $2 $3 "-" $4 $5 $6)}'
Hexadecimal without Prefix
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print tolower($1 $2 $3 $4 $5 $6)}'
Hexadecimal with Prefix
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print tolower("0x" $1 $2 $3 $4 $5 $6)}'
Hexadecimal with Postfix
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 $2 $3 $4 $5 $6 "h")}'
PXE
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 " " $2 " " $3 " " $4 " " $5 " " $6)}'
PostgreSQL
gawk 'BEGIN {FPAT="[[:xdigit:]]{2}"};{if(NF==6)print toupper($1 $2 $3 ":" $4 $5 $6)}'

POSIX Compatible One-Liners Using tr and sed

In the case that only valid MAC addresses separated by whitespace are used as input, POSIX provides tools for one-line command pipelines using tr and sed that fulfill the role of macfmt. Each command pipeline is based on the same tr invocation to remove all but the hexadecimal digits of the MAC address and conserving whitespace, followed by case conversion and digit grouping according to the target format.

Cisco
tr -cd '[:xdigit:][:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/\([[:xdigit:]]\{4\}\)\([[:xdigit:]]\{4\}\)\([[:xdigit:]]\{4\}\)/\1.\2.\3/g'
Linux
tr -cd '[:xdigit:][:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)/\1:\2:\3:\4:\5:\6/g'
Enterasys
tr -cd '[:xdigit:][:space:]' | tr '[:lower:]' '[:upper:]' | sed 's/\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)/\1-\2-\3-\4-\5-\6/g'
Cabletron
tr -cd '[:xdigit:][:space:]' | tr '[:lower:]' '[:upper:]' | sed 's/\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)/\1:\2:\3:\4:\5:\6/g'
Broadcom
tr -cd '[:xdigit:][:space:]' | tr '[:lower:]' '[:upper:]' | sed 's/\([[:xdigit:]]\{4\}\)\([[:xdigit:]]\{4\}\)\([[:xdigit:]]\{4\}\)/\1:\2:\3/g'
VMPS
tr -cd '[:xdigit:][:space:]' | tr '[:lower:]' '[:upper:]' | sed 's/\([[:xdigit:]]\{4\}\)\([[:xdigit:]]\{4\}\)\([[:xdigit:]]\{4\}\)/\1.\2.\3/g'
NetSight
tr -cd '[:xdigit:][:space:]' | tr '[:lower:]' '[:upper:]' | sed 's/\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)\([[:xdigit:]]\{2\}\)/\1.\2.\3.\4.\5.\6/g'
HP
tr -cd '[:xdigit:][:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/\([[:xdigit:]]\{6\}\)\([[:xdigit:]]\{6\}\)/\1-\2/g'
Hexadecimal without Prefix
tr -cd '[:xdigit:][:space:]' | tr '[:upper:]' '[:lower:]'
Hexadecimal with Prefix
tr -cd '[:xdigit:][:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/\([[:xdigit:]]\{12\}\)/0x\1/g'


back to my homepage.