#!/bin/bash
# changing ethernet naming to 'predcitable names' - good info at
# https://wiki.debian.org/NetworkInterfaceNames#THE_.22PREDICTABLE_NAMES.22_SCHEME
THIS=$(basename "$0")
VERSION="0.4 [13 Sep 2025]"
COLUMNS="$(stty size 2>/dev/null||echo 80)"; COLUMNS="${COLUMNS##* }"
set -o pipefail
unset HELP; unset CHANGELOG; unset QUIET
while getopts ":hlqw" optname; do
	case "$optname" in
		"h")	HELP="y";;
		"l")	CHANGELOG="y";;
		"q")	QUIET="y";;
		"w")	COLUMNS=30000;; #suppress line-breaking
		"?")	echo "Unknown option $OPTARG"; exit 1;;
		":")	echo "No argument value for option $OPTARG"; exit 1;;
		*)	# Should not occur
			echo "Unknown error while processing options"; exit 1;;
	esac
done
shift $((OPTIND-1))
[[ -z $QUIET ]] && { echo -e "\n$THIS v$VERSION by Dominic (try -h for help)\n${THIS//?/=}\n"; }
if [[ -n $HELP ]]; then
	echo -e "$THIS shows the current names, the 'biosdevnames' (if biosdevname \
is installed) and the 'predictable names' \
of network devices on a host Linux/GNU system, and together with the help \
information below may be helpful if you \
have a modern system and want to migrate the network device naming scheme (especially \
from a legacy naming scheme to the modern Predictable Names Scheme).

Background: On most modern Linux/GNU systems the Predictable \
Names Scheme (see below, not to be confused with the *Persistent* Names \
Scheme) is used by default (via udev and systemd) to select names for \
network devices (although it can exceptionally be overridden to use names \
of your choosing - for example, if using netplan, in \
/etc/netplan/config.yaml). However a \
system that has been in existence for a number of years is likely to \
retain legacy network device name settings, even if it has otherwise \
been updated.

The idea of the Predictable Names Scheme is to ensure that devices have a \
consistent name even if other things on the system change. One price paid \
for this is that the names are less easy on the eye e.g. wlp2s0 instead of \
the old-style wlan0.

To change the network devices naming scheme in use on a system, \
read the guidance below. Be careful as it may break other things: for \
example if using netplan you may need to update network device names in \
/etc/netplan/config.yaml (then do 'netplan apply') or if using \
systemd-networkd without netplan you may need to update \
/etc/network/interfaces.

Further information can be found at \
https://wiki.debian.org/NetworkInterfaceNames and \
https://lists.ubuntu.com/archives/ubuntu-devel/2015-May/038761.html.

Naming Schemes: Network devices are identified and named \
at boot time according to a naming scheme. You can change the scheme in use \
by following the instructions below.

 1. [Legacy] Persistent Names Scheme: This, if set up, may (always?) \
override any of the other schemes below. Originally based on udev rule \
/lib/udev/rules.d/75-persistent-net-generator.rules which on first \
boot creates a MAC address -> current name mapping and writes \
/etc/udev/rules.d/70-persistent-net.rules. It was retired a while ago \
(for Debian/Ubuntu) but may persist on long-standing systems. To remove it, \
ensure you have kernel settings for the Predictable Names Scheme (below), and:
    rm /etc/udev/rules.d/70-persistent-net.rules 2>/dev/null && \\
    ln -s /dev/null /etc/udev/rules.d/75-persistent-net-generator.rules
and/or (to force pickup of new bios network device names by \
/lib/udev/rules.d/80-net-setup-link.rules):
    [[ -s /lib/udev/rules.d/80-net-setup-link.rules ]] && \\
    rm /etc/udev/rules.d/80-net-setup-link.rules 2>/dev/null

 2. [Legacy] Old Simple Scheme: Use kernel options \
'net.ifnames=0 biosdevname=0', \
and ensure that it is not overridden by the Persistent Names Scheme (above). \
Network device names at boot time follow the old convention of \
eth0 / eth1 etc, with some risk of existing devices being renumbered \
in unpredictable ways if a network device is added or taken away.

 3. [Legacy] Biosdevname Scheme: Use kernel options \
'net.ifnames=0 biosdevname=1', \
and ensure that it is not overridden by the Persistent Names Scheme (above), \
and that program biosdevname is installed. However biosdevname is now \
largely superseded and if it is \
still active on your system you should consider migrating to the \
Predictable Names Scheme (below).

 4. Predictable Names Scheme: Use kernel options \
'net.ifnames=1 biosdevname=0', \
and ensure that it is not overridden by the Persistent Names Scheme (above). \
At the time of writing (2020) this is the preferred scheme in most situations.

Notes:
 1. The easiest way to alter a kernel option permanently is to set it \
using space-separated settings in GRUB_CMDLINE_LINUX_DEFAULT in \
/etc/default/grub before doing 'update-grub'.

 2. If program 'biosdevname' is installed, the kernel may (but might not) \
use the biosdevname scheme unless you explicitly set biosdevname=0 in \
kernel options. If program 'biosdevname' is not installed, you should \
not need the biosdevname=0 parameter (and biosdevname=1 should have \
no effect).

 3. Modern OSes such as Debian 9+ and Ubuntu 16.04+ use net.ifnames=1 \
as default so this does not have to specified. Older OSes use net.ifnames=0 \
as default.

 4. After making any changes, to ensure they are propagated through to \
the boot sequence, do:
    update-grub && update-initramfs -u

Usage       :
    $THIS [options]

Options     :  -h  - show this help and exit
               -l  - show changelog and exit
               -q  - only show device names, no other noise

Dependencies:  udevadm [biosdevname - not required but used if present]

License: Copyright © 2020 Dominic Raferd. Licensed under the Apache License, \
Version 2.0 (the \"License\"); you may not use this file except in compliance \
with the License. You may obtain a copy of the License at \
https://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable \
law or agreed to in writing, software distributed under the License is \
distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY \
KIND, either express or implied. See the License for the specific language \
governing permissions and limitations under the License.
"|fold -sw"$COLUMNS"
elif [[ -n $CHANGELOG ]]; then
	[[ -n $HELP ]] && echo "Changelog:"
	echo -e "\
0.4 [13 Sep 2025]: make shellcheck-compliant
0.3 [25 Jun 2020]: updated help
0.2 [05 Jun 2020]: added formal help, changelog, make publishable
0.1 [04 Jun 2020]: initial version
"|fold -sw"$COLUMNS"
fi
[[ -n $HELP$CHANGELOG ]] && exit
if [[ -z $QUIET ]]; then
	echo -e "Network devices on system '$HOSTNAME'\n----------------------------${HOSTNAME//?/-}"
	SEDMOD="1icurrent_name: biosdevname: predictable_name\n-------------: ----------------: ----------------"
else
	unset SEDMOD
fi
while read -r ETHDEVFILE; do echo -n "$(basename "$ETHDEVFILE"): $(biosdevname -i "$(basename "$ETHDEVFILE")" 2>/dev/null): "; udevadm test-builtin net_id "$ETHDEVFILE" 2>/dev/null|grep "ID_NET_NAME_"|sed 's/_FROM_DATABASE=/1 /;s/_ONBOARD=/2 /;s/_SLOT=/3 /;s/_PATH=/4 /;s/_MAC=/5 /'|sort -n|head -n1|cut -d" " -f2; done < <(find /sys/class/net -type l -not -name lo)|sed "$SEDMOD"|column -s: -t
