Issue
I will occasionally search aggregate logs files on my syslog server for a specific MAC address. Since each source uses a different format for MAC addresses, I usually use this command:
less syslog.log | grep -i -E '56[:-\.]?ea[:-\.]?b6[:-\.]?a6[:-\.]?82[:-\.]?5e'
Which will find the address regardless of the format or case (56eab6a6825e
, 56ea.b6a6.825e
, 56:ea:b6:a6:82:5e
, 56-EA-B6-A6-82-5E
).
I have this command saved in text file so I can just replace each hex pair with the relevant digits and paste it in, but is there an elegant way format my regex where I can have the whole address together? For example:
less syslog.log | grep -i -E '56eab6a6825e[:-\.]?(anywhereinthestring)'
I basically want to be more lazy when searching, but I don't understand lookarounds enough to know if they are applicable in this case. Is this even possible?
Solution
Simply store the mac-address to search in a variable and use Bash's replace expanded value to generate the Regex for grep
:
mac='56:ea:b6:a6:82:5e'
# Compose a regex on-the fly by replacing all colons with [:.-]?
grep -iE "${mac//:/[:.-]?}"
Or same as a function:
grepmac() {
# Usage:
# grepmac MAC_ADDRESS FILE [FILE]...
# Parses input argument 1 as mac-address
# regardless if it uses delimiters or not.
# Returns failure if input argument 1 is not a mac-address.
[[ $1 =~ ([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2}) ]] || return 1
# Sets delimiter locally to : to join matches with colon
local -- IFS=:
# Joins matches except first to get a colon-delimited mac-address
mac="${BASH_REMATCH[*]:1}"
# Shifts out first argument away to only keep remaining file paths
shift
# Composes a regex by replacing colons in mac-address by [:.-]?
# which matches optional delimiter with : . or -
regex=${mac//:/[:.-]?}
# Performs the actual search
grep -iE "$regex" "$@"
}
Traced execution of grepmac
:
$ set -x; grepmac 56eab6a6825e
+ grepmac 56eab6a6825e
+ [[ 56eab6a6825e =~ ([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2})[:.-]?([[:xdigit:]]{2}) ]]
+ IFS=:
+ mac=56:ea:b6:a6:82:5e
+ shift
+ regex='56[:.-]?ea[:.-]?b6[:.-]?a6[:.-]?82[:.-]?5e'
+ grep --color=auto -iE '56[:.-]?ea[:.-]?b6[:.-]?a6[:.-]?82[:.-]?5e'
Answered By - Léa Gris Answer Checked By - Timothy Miller (WPSolving Admin)