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

 

posted @ 2025-06-24 17:01  凡人半睁眼  阅读(141)  评论(0)    收藏  举报