对比 链接到标题

NetBird 和 Tailscale 都是 mesh VPN,但 CLI 体验有个明显差距:

操作 Tailscale NetBird
查看节点列表 tailscale status — 简洁表格 netbird status — 只显示本机状态
查看详情 tailscale status --json netbird status --detail — 散文体

tailscale status 输出是这样的:

100.121.*.*  peer-a     linux   -
100.121.*.*  server     linux   -
100.121.*.*  laptop     macOS   -

netbird status --detail 的节点信息散布在两处:

  • Peers detail 区块:每个对端分多行(FQDN、IP、Status)
  • Summary 区块:本地节点的 FQDN 和 IP 在底部

解析思路 链接到标题

以 Peers detail 中的一段为例:

 peer-a.netbird.selfhosted:
  NetBird IP: 100.121.*.*
  NetBird IPv6: fdd2:*:*:*:*:*:*:*
  Public key: xJwCVGGIjZGeEKzzPEXtcZZav2HIoYtLcfyjOyH9KR0=
  Status: Connected

需要提取的三行:

  1. 缩进的主机名行(前面有一个空格 + 主机名 + :
  2. NetBird IP:
  3. Status:

本地节点在 Summary 中格式相似,但主机名以 FQDN: 开头。

实现 链接到标题

nb-list() {
  (echo "FQDN                              IP                Status"
   netbird status --detail | awk '
     /^ [a-zA-Z]/ { name = $1; sub(/:$/, "", name) }
     /NetBird IP:/ { ip = $NF }
     /Status:/ {
       status = $NF
       if (name) printf "%-35s %-18s %s\n", name, ip, status
       name = ""; ip = ""
     }
     /^FQDN:/ { local_name = $NF }
     /^NetBird IP:/ && !/NetBird IPv6/ { local_ip = $NF }
   END {
     if (local_name) printf "%-35s %-18s %s\n", local_name, local_ip, "Connected"
   }') | column -t
}

关键点:

  • /^ [a-zA-Z]/ — 匹配开头带一个空格的 FQDN 行,去掉末尾冒号作为节点名
  • name = ""; ip = "" 在打印后立即清空,避免后续无关行误触
  • Summary 部分用独立的 local_name / local_ip 变量存放,END 块输出

效果 链接到标题

FQDN                          IP               Status
peer-a.netbird.selfhosted     100.121.*.*      Connected
server.netbird.selfhosted     100.121.*.*      Connected
laptop.netbird.selfhosted     100.121.*.*/16   Connected

含本地节点,与远程对端并列。

保存 链接到标题

将函数添加到 ~/.zshrc,source 后即可使用:

source ~/.zshrc
nb-list

替代方案 链接到标题

  • sudo wg show — 直接看 WireGuard 对端(最底层)
  • Dashboard 界面 — 自托管 Dashboard 地址
  • API — 用 Personal Access Token 调 GET /api/peers