chore: updated wifi status script 0e9f5de5
Steve · 2026-08-19 23:56 1 file(s) · +66 −16
scripts/wifi-status +66 −16
1 1
#!/bin/sh
2 2
# Requires: iw
3 -
# Prints the wireless link state with a Nerd Font icon, for the status bar
4 -
# and menus. The icon tracks signal strength while connected, so it moves
5 -
# as the link does.
6 -
# Usage: wifi-status [-p|--plain] [IFACE]   (default: first wireless interface)
3 +
# Prints the link state with a Nerd Font icon, for the status bar and menus.
4 +
# Wireless is the subject: the icon tracks signal strength while connected,
5 +
# so it moves as the link does. When wifi is not carrying traffic it falls
6 +
# back to reporting a live wired link rather than saying "off" while the
7 +
# machine is plainly online.
8 +
# Usage: wifi-status [-p|--plain] [-w|--wifi-only] [IFACE]
9 +
#   -p  plain output, no Nerd Font icon (for terminals without one)
10 +
#   -w  never fall back to wired, even with no wifi
11 +
#   IFACE  wireless interface to report (default: the first one the kernel
12 +
#          lists); naming one implies -w, since the question was about it
7 13
set -u
8 14
9 15
PLAIN=0
10 -
case "${1:-}" in
11 -
    -p|--plain) PLAIN=1; shift ;;
12 -
esac
16 +
WIFI_ONLY=0
17 +
18 +
while [ $# -gt 0 ]; do
19 +
    case "$1" in
20 +
        -p|--plain)     PLAIN=1 ;;
21 +
        -w|--wifi-only) WIFI_ONLY=1 ;;
22 +
        -*) echo "usage: wifi-status [-p] [-w] [IFACE]" >&2; exit 2 ;;
23 +
        *) break ;;
24 +
    esac
25 +
    shift
26 +
done
13 27
14 -
# ICON_ONLY/no-icon output goes through this so every exit path is consistent.
28 +
# Every exit path prints through this, so -p only has to be handled once.
15 29
say() {
16 30
    if [ "$PLAIN" -eq 1 ]; then
17 31
        echo "$2"
20 34
    fi
21 35
}
22 36
23 -
# Ask the kernel which interfaces are wireless rather than assuming wlan0.
24 -
IFACE="${1:-$(iw dev 2>/dev/null | awk '$1 == "Interface" { print $2; exit }')}"
37 +
# A wired interface counts only if it is a real NIC (a `device` symlink rules
38 +
# out docker0, tailscale0 and the veths), is up, and holds a v4 address —
39 +
# that last part is what says it can actually carry traffic.
40 +
wired_iface() {
41 +
    for path in /sys/class/net/*; do
42 +
        iface=${path##*/}
43 +
        [ "$iface" = "lo" ] && continue
44 +
        [ -d "$path/wireless" ] || [ -e "$path/phy80211" ] && continue
45 +
        [ -e "$path/device" ] || continue
46 +
        [ "$(cat "$path/operstate" 2>/dev/null)" = "up" ] || continue
47 +
        ip addr show "$iface" 2>/dev/null | grep -q "inet " || continue
48 +
        echo "$iface"
49 +
        return 0
50 +
    done
51 +
    return 1
52 +
}
53 +
54 +
# 󰈀 wired link carrying traffic. Only consulted once wifi has come up empty,
55 +
# so a working wifi connection always wins the block.
56 +
fallback() {
57 +
    [ "$WIFI_ONLY" -eq 1 ] && return 1
58 +
    WIRED=$(wired_iface) || return 1
59 +
    say "󰈀" "$WIRED"
60 +
    exit 0
61 +
}
62 +
63 +
if [ -n "${1:-}" ]; then
64 +
    # An explicitly named interface is the whole question — no wired fallback,
65 +
    # so callers like wifi-connect report on the link they just brought up.
66 +
    IFACE="$1"
67 +
    WIFI_ONLY=1
68 +
else
69 +
    # Ask the kernel which interfaces are wireless rather than assuming wlan0.
70 +
    IFACE=$(iw dev 2>/dev/null | awk '$1 == "Interface" { print $2; exit }')
71 +
fi
25 72
26 73
# 󰤮 no wireless hardware at all, 󰤭 card present but down/unassociated,
27 74
# 󰤫 associated without a lease, 󰤟󰤢󰤥󰤨 connected at rising signal strength.
28 75
if [ -z "$IFACE" ]; then
76 +
    fallback
29 77
    say "󰤮" "none"
30 78
    exit 0
31 79
fi
32 80
33 81
# `iw link` prints "Not connected." while the card is up but unassociated, and
34 82
# fails outright once wifi-disable has downed the link.
35 -
LINK=$(iw dev "$IFACE" link 2>/dev/null) || { say "󰤭" "off"; exit 0; }
83 +
LINK=$(iw dev "$IFACE" link 2>/dev/null) || { fallback; say "󰤭" "off"; exit 0; }
36 84
37 85
case "$LINK" in
38 86
    "Connected to"*) ;;
39 -
    *) say "󰤭" "off"; exit 0 ;;
87 +
    *) fallback; say "󰤭" "off"; exit 0 ;;
40 88
esac
41 89
42 90
SSID=$(printf '%s\n' "$LINK" | sed -n 's/^[[:space:]]*SSID: \(..*\)$/\1/p')
43 91
[ -n "$SSID" ] || SSID="unknown"
44 92
45 -
# Associated but without a lease carries no traffic — say so rather than
46 -
# showing a network name that looks connected.
93 +
# Associated but without a lease carries no traffic, so wired wins here too;
94 +
# without one, name the network but say the lease is missing rather than
95 +
# showing an SSID that looks connected.
47 96
if ! ip addr show "$IFACE" 2>/dev/null | grep -q "inet "; then
97 +
    fallback
48 98
    say "󰤫" "$SSID (no ip)"
49 99
    exit 0
50 100
fi
53 103
# -50 is excellent, -70 is the edge of usable.
54 104
DBM=$(printf '%s\n' "$LINK" | awk '/signal:/ { printf "%d", $2; exit }')
55 105
56 -
if [ -z "$DBM" ];      then ICON="󰤨"   # no signal line (some drivers) — assume good
106 +
if   [ -z "$DBM" ];      then ICON="󰤨"   # no signal line (some drivers) — assume good
57 107
elif [ "$DBM" -ge -50 ]; then ICON="󰤨"
58 108
elif [ "$DBM" -ge -60 ]; then ICON="󰤥"
59 109
elif [ "$DBM" -ge -70 ]; then ICON="󰤢"
60 -
else                         ICON="󰤟"
110 +
else                          ICON="󰤟"
61 111
fi
62 112
63 113
say "$ICON" "$SSID"