Created
March 5, 2026 12:11
-
-
Save jvarn/65b300e244068637996ac1b0710c5717 to your computer and use it in GitHub Desktop.
Retrieve the MAC address of a network interface on a local or remote host (macOS or Linux)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ----------------------------------------------------------------------------- | |
| # getmacaddress.sh | |
| # | |
| # Retrieve the MAC address of a network interface on a local or remote host. | |
| # | |
| # The script connects to the specified host (via SSH if the host is not the | |
| # local machine) and attempts to retrieve the MAC address of the specified | |
| # network interface. | |
| # | |
| # Behaviour: | |
| # - If no interface is specified, the script defaults to "en0". | |
| # - If the interface exists, the MAC address is printed to stdout. | |
| # - If the interface does not exist, the script lists available interfaces | |
| # and prompts the user to select one interactively. | |
| # | |
| # The script supports both macOS and Linux systems: | |
| # - macOS: uses `ifconfig` to obtain the MAC address | |
| # - Linux: reads `/sys/class/net/<interface>/address` | |
| # | |
| # Rationale: | |
| # Many modern Linux distributions no longer install the legacy | |
| # `net-tools` package by default (which provides `ifconfig`). Rather | |
| # than assuming its presence, the script reads the MAC address | |
| # directly from `/sys/class/net`, which is part of the standard | |
| # Linux kernel sysfs interface and is available on virtually all | |
| # Linux systems. | |
| # | |
| # SSH is only used when the requested host differs from the local hostname | |
| # (case-insensitive comparison). | |
| # | |
| # Usage: | |
| # getmacaddress.sh <host> [interface] | |
| # | |
| # Examples: | |
| # getmacaddress.sh computername1.local | |
| # getmacaddress.sh computername2.local enp1s0 | |
| # getmacaddress.sh computername3.local en1 | |
| # | |
| # Arguments: | |
| # host Target hostname or SSH host alias | |
| # interface Optional network interface (default: en0) | |
| # | |
| # Exit codes: | |
| # 0 Success (MAC address printed) | |
| # 1 Invalid input | |
| # 2 Interface not found or MAC address could not be determined | |
| # | |
| # Requirements: | |
| # - bash (compatible with macOS bash 3.2+) | |
| # - ssh (for remote hosts) | |
| # - ifconfig (macOS) or /sys/class/net (Linux) | |
| # | |
| # Installation (optional): | |
| # To make the script available system-wide, copy it to a directory | |
| # on your PATH, for example: | |
| # | |
| # cp getmacaddress.sh /usr/local/bin/getmacaddress | |
| # chmod +x /usr/local/bin/getmacaddress | |
| # | |
| # You can then run it from anywhere, e.g.: | |
| # | |
| # getmacaddress computername.local | |
| # | |
| # (On macOS and many Linux systems, /usr/local/bin is already included | |
| # in the default PATH.) | |
| # | |
| # Author: Jeremy Varnham https://github.com/jvarn | |
| # License: MIT | |
| # ----------------------------------------------------------------------------- | |
| usage() { | |
| echo "Usage: $(basename "$0") <host> [interface]" | |
| echo "Example: $(basename "$0") quark en1" | |
| echo "If interface is omitted, en0 is used." | |
| } | |
| if [[ -z "$1" ]]; then | |
| usage | |
| exit 1 | |
| fi | |
| HOST="$1" | |
| INTERFACE="${2:-en0}" | |
| LOCAL_HOST=$(hostname | tr '[:upper:]' '[:lower:]') | |
| TARGET_HOST=$(echo "$HOST" | tr '[:upper:]' '[:lower:]') | |
| # POSIX-sh compatible remote/local commands (NO [[ ... ]]) | |
| GET_MAC_CMD=' | |
| case "$OSTYPE" in | |
| darwin*) | |
| ifconfig '"$INTERFACE"' 2>/dev/null | awk "/ether/{print \$2; exit}" | |
| ;; | |
| *) | |
| cat /sys/class/net/'"$INTERFACE"'/address 2>/dev/null | head -n 1 | |
| ;; | |
| esac | |
| ' | |
| LIST_IFACES_CMD=' | |
| case "$OSTYPE" in | |
| darwin*) | |
| ifconfig 2>/dev/null | awk " | |
| /^[A-Za-z0-9._-]+:/{iface=\$1; sub(/:$/, \"\", iface)} | |
| /ether[[:space:]]/{print iface} | |
| " | sort -u | |
| ;; | |
| *) | |
| for p in /sys/class/net/*/address; do | |
| iface=${p%/address}; iface=${iface##*/} | |
| [ "$iface" = "lo" ] && continue | |
| echo "$iface" | |
| done | sort -u | |
| ;; | |
| esac | |
| ' | |
| run_cmd() { | |
| # $1 = command string | |
| if [[ "$TARGET_HOST" == "$LOCAL_HOST" ]]; then | |
| sh -c "$1" | |
| else | |
| # run using /bin/sh on the remote, but keep the script POSIX-compatible | |
| ssh "$HOST" "sh -c $(printf '%q' "$1")" | |
| fi | |
| } | |
| MAC="$(run_cmd "$GET_MAC_CMD" | tr -d '\r' | head -n 1)" | |
| if [[ -n "$MAC" ]]; then | |
| echo "$MAC" | |
| exit 0 | |
| fi | |
| echo "Interface \"$INTERFACE\" does not exist on $HOST." | |
| #mapfile -t IFACE_ARRAY < <(run_cmd "$LIST_IFACES_CMD" | tr -d '\r') | |
| # Build IFACE_ARRAY (bash 3.2 compatible: no mapfile) | |
| IFACE_ARRAY=() | |
| while IFS= read -r line; do | |
| [[ -n "$line" ]] && IFACE_ARRAY+=("$line") | |
| done < <(run_cmd "$LIST_IFACES_CMD" | tr -d '\r') | |
| if [[ ${#IFACE_ARRAY[@]} -eq 0 ]]; then | |
| echo "(No interfaces with a MAC address were detected.)" | |
| exit 2 | |
| fi | |
| echo "Please choose one of the following interfaces:" | |
| for i in "${!IFACE_ARRAY[@]}"; do | |
| printf "%2d) %s\n" $((i+1)) "${IFACE_ARRAY[$i]}" | |
| done | |
| echo | |
| read -p "Enter number: " CHOICE | |
| if ! [[ "$CHOICE" =~ ^[0-9]+$ ]] || (( CHOICE < 1 || CHOICE > ${#IFACE_ARRAY[@]} )); then | |
| echo "Invalid selection." | |
| exit 1 | |
| fi | |
| INTERFACE="${IFACE_ARRAY[$((CHOICE-1))]}" | |
| MAC="$(run_cmd " | |
| case \"\$OSTYPE\" in | |
| darwin*) | |
| ifconfig $INTERFACE 2>/dev/null | awk '/ether/{print \$2; exit}' | |
| ;; | |
| *) | |
| cat /sys/class/net/$INTERFACE/address 2>/dev/null | head -n 1 | |
| ;; | |
| esac | |
| " | tr -d '\r')" | |
| if [[ -n "$MAC" ]]; then | |
| echo | |
| echo "$MAC" | |
| exit 0 | |
| fi | |
| echo "Unable to determine MAC address." | |
| exit 2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment