nmcli 之Wi-Fi 设置
一、理论
1、nmcli
是 Linux 系统中 NetworkManager 提供的命令行工具,
用于 管理网络连接,特别适用于图形界面不可用或自动化脚本环境下。
🧾 基本信息
-
全称:NetworkManager Command Line Interface
-
所属包:
NetworkManager
-
用途:配置 以太网、Wi-Fi、VLAN、桥接、代理、VPN 等连接
2、只看当前正在使用的连接
# nmcli connection show --active NAME UUID TYPE DEVICE xxx 7d1ab3e0-ba49-4ece-a59a-fd41be6ec5ab wifi wlp3s0 # nmcli device status DEVICE TYPE STATE CONNECTION wlp3s0 wifi 已连接 healsci enp1s0 ethernet 未托管 -- enp2s0 ethernet 未托管 -- lo loopback 未托管 --
3、查看详细信息
nmcli -p device show wlp3s0
4、实时扫描、列出周围的 Wi-Fi 热点
nmcli device wifi list
5、查看连接过的 “历史记录“
nmcli connection show
6、查看连接是静态还是动态
nmcli connection show hexxxi | grep ipv4.method ipv4.method: manual
7、修改Wi-Fi
修改配置文件方式:
cat /etc/NetworkManager/system-connections/healsci.nmconnection
8、查看密码
方法1: cat /etc/NetworkManager/system-connections/wifi-name.nmconnection 方法2(更方便): nmcli -s -g 802-11-wireless-security.psk connection show wifi-name
9、连接没有连过的
nmcli device wifi connect "xxx" --ask nmcli device wifi connect “xxxx" password 'your_password_here'
10、设置静态ip
nmcli connection modify xxx ipv4.method manual ipv4.addresses 192.168.1.100/24 ipv4.gateway 192.168.1.1 ipv4.dns "8.8.8.8 1.1.1.1" nmcli connection up xxx 连接名必须准确: 不是设备名(如 eth0),而是 nmcli connection show 中的 NAME。 接口必须由 NetworkManager 管理: 如果系统用了 netplan 或 systemd-networkd 管理接口,nmcli 不会生效。 CIDR 格式正确: 如 192.168.1.100/24,确保写的是 IP 加掩码。
11、查看信号强度
# iwconfig wlp3s0 wlp3s0 IEEE 802.11 ESSID:"xxxxxxx" Mode:Managed Frequency:5.24 GHz Access Point: D4:68:BA:86:04:9F Bit Rate=121.5 Mb/s Tx-Power=15 dBm Retry short limit:7 RTS thr:off Fragment thr:off Encryption key:off Power Management:on Link Quality=61/70 Signal level=-49 dBm Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0 Tx excessive retries:1 Invalid misc:3052 Missed beacon:0 # iw dev wlp3s0 link Connected to d4:68:ba:86:04:9f (on wlp3s0) SSID: xxxx freq: 5240 RX: 93389237 bytes (479148 packets) TX: 79328016 bytes (63432 packets) signal: -49 dBm rx bitrate: 216.0 MBit/s MCS 13 40MHz tx bitrate: 121.5 MBit/s MCS 6 40MHz bss flags: short-slot-time dtim period: 1 beacon int: 100
- Link Quality :链路质量为 61
/70
,表示信号质量约为74%
(计算方法:61/ 70 * 100% ≈ 87%
)。 - Signal level :信号强度为
-49 dBm
。- 信号强度的参考范围:
-30 dBm
到-50 dBm
:良好信号。-50 dBm
到-70 dBm
:中等信号。-70 dBm
以下:信号较弱。
-49 dBm
属于 良好信号强度 ,可能会影响连接稳定性。
- 信号强度的参考范围:
12、从静态切换为dhcp
nmcli connection modify healsci ipv4.method auto ipv4.ignore-auto-dns no nmcli connection up healsci
13、重载配置文件
# 热重启。不断开 nmcli device reapply wlp3s0 # 会断开连接 nmcli connection down [id] && nmcli connection up [id]
二、脚本工具
1、Wi-Fi 设置
提供四个功能:加入、删除、转静态、转dhcp
#!/bin/bash # Check NetworkManager service status if ! systemctl is-active --quiet NetworkManager; then echo "Error: NetworkManager is not running. Please start the service first!" exit 1 fi # Check root privileges if [ "$(id -u)" != "0" ]; then echo "Please run this script with sudo or as root" exit 1 fi # Main menu function show_menu() { clear echo "==================================" echo " WiFi Network Configuration Tool " current_wifi=$(nmcli connection show --active | tail -1 | awk '{print $1}') ip_method=$(nmcli connection show "$current_wifi" | grep ipv4.method | awk '{print $2}') if [ -n "$current_wifi" ] && [ -n "$ip_method" ]; then echo "Current WiFi: $current_wifi, $ip_method" else echo "Not connected to WiFi" fi echo "==================================" echo "1. Connect to a new WiFi network" echo "2. Delete saved WiFi network" echo "3. Configure static network" echo "4. Configure DHCP network" echo "5. Exit" echo "==================================" read -p "Select an option [1-5]: " choice } # Function: Join WiFi join_wifi() { echo -e "\nScanning for nearby WiFi networks..." nmcli device wifi rescan &> /dev/null sleep 2 # Display available networks echo -e "\nAvailable WiFi Networks:" nmcli device wifi list read -p "Enter WiFi SSID: " ssid if [ -z "$ssid" ]; then echo "Error: SSID cannot be empty!" return fi # Check if config already exists if nmcli -g NAME connection show | grep -q "^$ssid$"; then read -p "This network already exists. Connect now? [y/N]: " choice if [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then nmcli connection up "$ssid" fi return fi # Request password and connect read -sp "Enter WiFi password (hidden input): " password echo if [ -z "$password" ]; then echo "Warning: No password entered. Trying to connect to open network..." nmcli device wifi connect "$ssid" else nmcli device wifi connect "$ssid" password "$password" fi # Check result if [ $? -eq 0 ]; then echo -e "\n✓ Successfully connected to $ssid" else echo -e "\n✗ Connection failed. Please check password and network state" fi } # Function: Delete WiFi delete_wifi() { echo -e "\nSaved WiFi configurations:" nmcli --fields NAME,TYPE,UUID connection show | grep wifi read -p "Enter configuration name to delete: " conn_name if [ -z "$conn_name" ]; then echo "Error: Configuration name cannot be empty!" return fi # Validate existence if ! nmcli -g NAME connection show | grep -q "^$conn_name$"; then echo "Error: Configuration '$conn_name' not found!" return fi # Confirm deletion read -p "Confirm deletion of '$conn_name'? [y/N]: " choice if [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then nmcli connection delete "$conn_name" echo "✓ Configuration '$conn_name' deleted" else echo "Operation canceled" fi } # Function: Set static IP set_static_ip() { echo -e "\nSaved WiFi configurations:" nmcli --fields NAME,TYPE,DEVICE connection show | grep wifi read -p "Enter network name to configure: " conn_name if [ -z "$conn_name" ]; then echo "Error: Configuration name cannot be empty!" return fi # Validate existence if ! nmcli connection show "$conn_name" &> /dev/null; then echo "Error: Configuration '$conn_name' not found!" return fi # Get current device info device=$(nmcli -g connection.interface-name connection show "$conn_name") if [ -z "$device" ]; then echo "Error: Unable to get device information!" return fi # Get current gateway current_gateway=$(nmcli -g ip4.gateway connection show "$conn_name") # Get recommended values echo -e "\nCurrent network info:" ip_addr=$(ip -o -4 addr show dev $device | awk '{print $4}') gateway=${current_gateway:-$(ip route | grep default | grep $device | awk '{print $3}')} dns_servers=$(nmcli -g ip4.dns connection show "$conn_name" 2>/dev/null | tr '|' ' ') [ -z "$ip_addr" ] || echo "Current IP: $ip_addr" [ -z "$gateway" ] || echo "Current Gateway: $gateway" [ -z "$dns_servers" ] || echo "Current DNS: $dns_servers" # Get user input echo -e "\nEnter static IP configuration (Format: IP/CIDR)" read -p "Example: 192.168.1.100/24: " static_ip if [ -z "$gateway" ]; then read -p "Enter Gateway Address: " gateway else read -p "Enter Gateway [default: $gateway]: " new_gateway gateway=${new_gateway:-$gateway} fi if [ -z "$dns_servers" ]; then read -p "Enter DNS servers (space-separated): " dns_servers else read -p "Enter DNS servers [default: $dns_servers]: " new_dns dns_servers=${new_dns:-$dns_servers} fi # Apply static IP echo -e "\nApplying static IP configuration..." nmcli connection modify "$conn_name" \ ipv4.method manual \ ipv4.addresses "$static_ip" \ ipv4.gateway "$gateway" # Set DNS (clear first) nmcli connection modify "$conn_name" ipv4.dns "" nmcli connection modify "$conn_name" ipv4.dns "$dns_servers" # Restart connection echo "Restarting connection..." nmcli connection up "$conn_name" # Verify configuration if nmcli -g ipv4.method connection show "$conn_name" | grep -q manual; then echo -e "\n✓ Static IP configured successfully!" echo "New IP: $(nmcli -g ipv4.addresses connection show "$conn_name")" echo "DNS Servers: $(nmcli -g ipv4.dns connection show "$conn_name")" else echo -e "\n✗ Configuration failed. Please check input parameters" fi } # Function: Set DHCP set_dhcp() { echo -e "\nSaved WiFi configurations:" nmcli --fields NAME,TYPE,DEVICE connection show | grep wifi read -p "Enter network name to switch to DHCP: " conn_name if [ -z "$conn_name" ]; then echo "Error: Configuration name cannot be empty!" return 1 fi # Validate existence and type if ! nmcli connection show --active | grep -q "$conn_name"; then echo "Error: WiFi configuration '$conn_name' not found!" return 1 fi # Switch to DHCP echo -e "\nSwitching to DHCP..." if ! nmcli connection modify "$conn_name" \ ipv4.method auto \ ipv4.ignore-auto-dns no 2>/dev/null; then echo "Error: Failed to modify configuration!" return 1 fi # Reactivate connection if nmcli connection up "$conn_name"; then echo -e "\n✓ Successfully switched to DHCP" else echo -e "\n✗ Failed to activate connection" return 1 fi } # Main loop while true; do show_menu case $choice in 1) join_wifi ;; 2) delete_wifi ;; 3) set_static_ip ;; 4) set_dhcp ;; 5) echo "Exiting program"; exit 0 ;; *) echo "Invalid selection, please try again!"; sleep 1 ;; esac echo && read -p "Press Enter to continue..." -n 1 done
2、Wi-Fi监控
#!/bin/bash TARGET_IP="" LOG_FILE="/var/log/wifi_monitor.log" log() { local message="$(date '+%Y-%m-%d %H:%M:%S') | $1" echo "$message" | tee -a "$LOG_FILE" } # Check if TARGET_IP is valid IPv4 address is_valid_ip() { local ip="$1" local regex='^([0-9]{1,3}\.){3}[0-9]{1,3}$' if [[ -z "$ip" ]]; then log "Error: TARGET_IP is empty." return 1 elif [[ ! "$ip" =~ $regex ]]; then log "Error: TARGET_IP '$ip' is not a valid IPv4 address." return 1 else # Further check each octet to be between 0 and 255 IFS='.' read -r -a octets <<< "$ip" for octet in "${octets[@]}"; do if (( octet < 0 || octet > 255 )); then log "Error: TARGET_IP '$ip' is not a valid IPv4 address." return 1 fi done fi return 0 } # Check for active network connections (using nmcli) check_internet_connection() { if nmcli connection show --active | grep -q "ethernet\|wifi"; then log "Network status: There is an active network connection (online)" return 0 else log "Network status: No active network connection (offline)" return 1 fi } # Check if the target server is reachable check_server() { ping -c 3 "$TARGET_IP" > /dev/null 2>&1 if [ $? -eq 0 ]; then log "Server $TARGET_IP status: Reachable" return 0 else log "Server $TARGET_IP status: Unreachable" return 1 fi } # Restart Wi-Fi restart_wifi() { log "Attempting to restart Wi-Fi..." INTERFACE=$(nmcli -t --fields DEVICE dev wifi | head -n 1) if [ -n "$INTERFACE" ]; then nmcli device disconnect "$INTERFACE" > /dev/null 2>&1 sleep 5 nmcli device reapply "$INTERFACE" > /dev/null 2>&1 || nmcli radio wifi off && nmcli radio wifi on sleep 10 else log "Unable to get Wi-Fi interface name, skipping Wi-Fi restart" return 1 fi } # Reboot system reboot_system() { log "Network recovery failed, system will now reboot..." reboot } # Main logic main() { log "Starting network health check..." # Validate TARGET_IP first if ! is_valid_ip "$TARGET_IP"; then log "Invalid or missing TARGET_IP, exiting script." exit 1 fi check_internet_connection internet_ok=$? check_server server_ok=$? if [ $internet_ok -eq 0 ] && [ $server_ok -eq 0 ]; then log "Network status is normal, no action to do." else log "Network issue detected, attempting to fix..." restart_wifi # Re-check after restarting Wi-Fi check_internet_connection internet_ok=$? check_server server_ok=$? if [ $internet_ok -eq 0 ] && [ $server_ok -eq 0 ]; then log "Network has been restored." else log "Network still not restored, preparing to reboot system." reboot_system fi fi } main
补充:关于ip的验证
is_valid_ip() { local ip="$1" local regex='^([0-9]{1,3}\.){3}[0-9]{1,3}$' if [[ -z "$ip" ]]; then log "Error: TARGET_IP is empty." return 1 elif [[ ! "$ip" =~ $regex ]]; then log "Error: TARGET_IP '$ip' is not a valid IPv4 address." return 1 else # Further check each octet to be between 0 and 255 IFS='.' read -r -a octets <<< "$ip" for octet in "${octets[@]}"; do if (( octet < 0 || octet > 255 )); then log "Error: TARGET_IP '$ip' is not a valid IPv4 address." return 1 fi done fi return 0 }
local regex='^([0-9]{1,3}\.){3}[0-9]{1,3}$'
- 定义一个正则表达式
regex
来初步检查 IP 格式:^
表示开头;[0-9]{1,3}
表示由 1 到 3 位数字组成的一个“段”;\.
是点号;([0-9]{1,3}\.){3}
表示这种格式重复三次;- 最后再加上一个
[0-9]{1,3}
; $
表示结尾。- 所以这个正则匹配的是类似
xxx.xxx.xxx.xxx
的格式。
检查每个 octet 是否在 0~255 范围内
IFS='.' read -r -a octets <<< "$ip"
- 设置内部字段分隔符
IFS
为.
,然后使用read
将 IP 地址按.
分割成数组octets
。 -r
防止反斜杠被转义;-a octets
表示将结果保存到数组octets
;<<< "$ip"
是 here string 语法,把变量内容作为输入传递给命令。
for octet in "${octets[@]}"; do if (( octet < 0 || octet > 255 )); then log "Error: TARGET_IP '$ip' is not a valid IPv4 address." return 1 fi done
- 遍历分割后的每个“八位组”(即 IP 的每一部分);
- 使用算术运算
(( ))
判断它是否在0 ~ 255
范围之外; - 如果有任意一个不在范围内,就输出错误信息并返回
1
。
if ! is_valid_ip "$TARGET_IP"; then log "Invalid or missing TARGET_IP, exiting script." exit 1 fi
如果is_valid_ip "$TARGET_IP" return 任何一个非0 都为false (假) ! 取反为 true