#!/bin/bash # # Purpose : Find what's on the local network over mDNS (Avahi), for the # configure.d items that set up servers, printers and storage on it. # Source this file. # Every service Avahi can see, or only those of type $1 (e.g. _ipp._tcp), one # per line after waiting a few seconds for answers: # "name|type|host|address|port|txt". IPv4 only, so a machine isn't listed once # per address family. The name has Avahi's escapes decoded. mdns_services() { local name type host address port txt timeout 15 avahi-browse "${1:---all}" --resolve --terminate --parsable --no-db-lookup 2> /dev/null \ | awk -F';' '$1 == "=" && $3 == "IPv4"' \ | while IFS=';' read -r _ _ _ name type _ host address port txt; do printf '%s|%s|%s|%s|%s|%s\n' "$(mdns_unescape "$name")" "$type" "$host" "$address" "$port" "$txt" done | sort -u } # Avahi writes a space as \032 and a dot in a name as \. (decimal escapes) mdns_unescape() { local s="$1" out="" ch code escape='^([^\\]*)\\([0-9][0-9][0-9]|.)(.*)$' while [[ "$s" =~ $escape ]]; do out+="${BASH_REMATCH[1]}" code="${BASH_REMATCH[2]}" s="${BASH_REMATCH[3]}" if [[ "$code" == [0-9][0-9][0-9] ]]; then # shellcheck disable=SC2059 printf -v ch "\\$(printf %03o "$((10#$code))")" out+="$ch" else out+="$code" fi done echo "$out$s" } # This machine's own .local name, which mdns_hosts leaves out mdns_own_host() { echo "$(hostnamectl hostname 2> /dev/null || cat /etc/hostname).local" } # The other machines on the network: one .local name per line mdns_hosts() { local own own="$(mdns_own_host)" mdns_services | cut -d'|' -f3 | grep -vixF "$own" | sort -u }