You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash并行ping监控IP列表主机上下线脚本开发及问题排查

问题根因

你写的脚本持续监控模块异常的核心原因有3个:

  • 多进程逻辑使用场景错误:你给每个IP单独启动了一个常驻的check_health子进程,每个子进程的内存空间完全独立,既无法维护全量IP的状态映射,xargs按行传参时遇到空行、特殊字符还会出现参数丢失,最终表现为仅部分IP被监控。
  • ping参数跨平台不兼容:脚本里用的-t 1是BSD/macOS版本ping的TTL参数,Linux系统下ping的超时参数为-W 1,参数错误会导致ping检测结果完全不准。
  • 状态存储逻辑缺陷:原参考脚本2用up+序号的动态变量存状态,一旦IP列表读取顺序错乱、漏行,就会出现IP和状态不匹配的问题。
优化方案

直接重构逻辑,同时满足两个参考脚本的核心能力:

  • 读取IP文件时一次性过滤空行、#开头的注释行,存入全局数组,从根源避免读文件漏行问题。
  • 首次存活检测保留xargs多进程并行逻辑,默认8个并发(可自定义)快速完成初始状态扫描。
  • 持续监控阶段每轮检测仍用多进程并行ping,所有检测结果返回主进程,主进程用关联数组统一维护每个IP的上一次状态,仅当状态发生变化时输出日志,既保证检测速度,又不会出现状态隔离、IP漏检的问题。
  • 做ping参数跨平台兼容,自动识别系统类型适配参数,Linux、macOS都能正常跑。
  • 保留原脚本的彩色输出、小黄鸭启动界面,去掉冗余的重复函数。
修复后可直接运行的脚本
#!/bin/bash
set -eo pipefail
trap 'echo -e "\n\033[1;33m监控已退出\033[0m"; exit 0' INT TERM

# 入参检查
if [ $# -lt 1 ]; then
    echo "用法: $0 <IP列表文件路径> [并行进程数,默认8]"
    exit 1
fi
HOST_FILE=$1
MAX_PROC=${2:-8}

# 加载IP列表,过滤空行和注释行
mapfile -t HOST_LIST < <(grep -vE '^\s*$|^\s*#' "$HOST_FILE")
if [ ${#HOST_LIST[@]} -eq 0 ]; then
    echo "错误: IP列表文件为空或不存在"
    exit 1
fi

# 跨平台ping函数
ping_host() {
    local ip=$1
    if [[ "$(uname)" == "Linux" ]]; then
        ping -c 1 -W 1 "$ip" >/dev/null 2>&1
    else
        # macOS/BSD
        ping -c 1 -W 1 -t 1 "$ip" >/dev/null 2>&1
    fi
    echo "$ip $?"
}
export -f ping_host

# 彩色输出函数
print_log() {
    local ip=$1
    local status=$2
    local date_str
    date_str=$(date '+%d/%m/%Y %H:%M:%S')
    if [ $status -eq 0 ]; then
        echo -e "|\033[1;36m  $date_str \033[0m" "|\033[1;32m Node |"$ip "| UP \033[0m" | column -t -s "|"
    else
        echo -e "|\033[1;36m  $date_str \033[0m" "|\033[1;31m Node |"$ip "| DOWN \033[0m" | column -t -s "|"
    fi
}

# 启动欢迎界面
print_banner() {
    local textpink textyellow external_ip internal_ip my_name
    textpink=$(tput setaf 5)
    textyellow=$(tput setaf 11)
    external_ip=$(curl -s --connect-timeout 2 ifconfig.me || echo "获取失败")
    internal_ip=$(ip addr 2>/dev/null | grep -Eo 'inet ([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -1 || ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -1)
    my_name=$(hostname)

    clear
    echo -e "${textpink}================================================================"
    cat << "EOF"
                  __                         __
              ___( o)>       DuckLab       <(o )___
              \ <_. )        Monitor        ( ._> /
               `---'                         `---' 
EOF
    echo -e "${textpink}================================================================"
    echo -e "${textyellow}                    Press <CTRL+C> to exit.                   "
    echo -e "${textpink}================================================================"
    echo -e "\033[1;36m  $internal_ip \033[0m" "     ${textpink}|     " "\033[1;36m $my_name \033[0m" "     ${textpink}|     " "\033[1;36m $external_ip \033[0m"
    echo -e "${textpink}================================================================"
    echo -e "已加载 ${#HOST_LIST[@]} 个监控目标, 并行进程数: $MAX_PROC"
    echo -e "-------------------------------------------------------------"
}

# 首次并行检测
first_scan() {
    echo "正在执行首次存活检测..."
    while read -r ip ret; do
        print_log "$ip" "$ret"
        LAST_STATUS[$ip]=$ret
    done < <(printf "%s\n" "${HOST_LIST[@]}" | xargs -n 1 -P "$MAX_PROC" -I{} bash -c 'ping_host "$@"' _ {})
    echo -e "-------------------------------------------------------------"
    echo "首次检测完成, 进入持续监控模式, 仅状态变更时输出日志:"
}

# 主逻辑
declare -A LAST_STATUS
print_banner
first_scan

# 持续监控循环
while true; do
    # 并行获取所有IP当前状态
    while read -r ip ret; do
        # 状态变化才输出
        if [ "${LAST_STATUS[$ip]}" != "$ret" ]; then
            print_log "$ip" "$ret"
            LAST_STATUS[$ip]=$ret
        fi
    done < <(printf "%s\n" "${HOST_LIST[@]}" | xargs -n 1 -P "$MAX_PROC" -I{} bash -c 'ping_host "$@"' _ {})
    sleep 1
done
使用说明
  • IP列表文件里每行写一个IP,支持空行、#开头的注释行,脚本会自动过滤。
  • 运行命令:chmod +x ping_monitor.sh && ./ping_monitor.sh ip_list.txt,如果要自定义并行数,在文件路径后面加数字就行,比如./ping_monitor.sh ip_list.txt 16就是16个并发。
  • 按Ctrl+C即可正常退出脚本。

内容的提问来源于stack exchange,提问作者Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 13:18:22