不能直接for循环串行ping,因每个IP需等待前一个完成(默认超时10秒),254个地址至少耗时254秒,且路由不可达时易卡死;生产环境仅适用于≤5个固定IP检测。

直接用 ping 做批量检测,不加并发控制就是串行执行,扫一个 /24 网段要 4 分钟以上;但硬上 1000 个线程又容易把系统资源打满、触发 ICMP 限速甚至被目标设备丢包。真正的平衡点在「可控并发 + 合理超时 + 错误隔离」。
为什么不能直接 for 循环调用 ping -c 1
串行执行意味着每个 IP 都得等前一个 ping 完(默认超时 10 秒),哪怕加了 -w 1,254 个地址也要至少 254 秒;更糟的是,一旦某个 IP 路由不可达或中间设备静默丢包,ping 可能卡住直到超时结束,整个脚本就挂在那里。实际生产环境里,这种写法只适合检查 5 个以内的固定 IP。
用命名管道(FIFO)控并发最稳
Linux 原生命名管道是控制并发数最轻量、最可靠的方式,不依赖额外工具,也不吃 Python 解释器开销。关键不是“多线程”,而是“最多同时跑 N 个 ping 进程”:
-
mkfifo创建管道,用文件描述符exec 9<>$fifo_file绑定读写端 - 先往管道里写入
$thread_num行空行,每消耗一行就代表一个 slot 被占用 - 每个 ping 任务启动前
read -u9占位,结束后echo >&9归还 slot - 必须配
wait等所有子进程结束,否则脚本提前退出导致结果丢失
示例节选(线程数设为 30):
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
thread_num=30
fifo_file="/tmp/ping_$$"
mkfifo "$fifo_file"
exec 9<>"$fifo_file"
for ((i=0; i<$thread_num; i++)); do echo; done >&9
while IFS= read -r ip; do
read -u9
{
if ping -c 1 -W 1 "$ip" >/dev/null 2>&1; then
echo "$ip: up"
else
echo "$ip: down"
fi
echo >&9
} &
done < iplist.txt
wait
exec 9>&-
fping 是更优的替代方案
如果目标机器允许装额外工具,fping 是专为批量探测设计的,天然支持并发和网段扫描,比手写管道脚本更少出错:
-
fping -f iplist.txt -p 100 -t 500 -a -q:从文件读 IP,每个间隔 100ms,超时 500ms,只输出存活 IP -
fping -g 192.168.1.0/24 -a:直接扫整个 CIDR,自动跳过广播和网络地址 - 注意:
fping默认需要 root 权限发原始 ICMP 包,普通用户可用fping -S指定源地址绕过部分限制
它底层用 select/poll 实现单进程高并发,不会 fork 出几百个子进程,CPU 和内存占用远低于 shell 管道方案。
别忽略 ICMP 层面的真实限制
即使脚本逻辑完全正确,也可能扫不到真实在线的主机——因为对方禁 ping:
- 内核参数
net.ipv4.icmp_echo_ignore_all = 1会直接丢弃所有 ICMP 请求 - iptables 规则如
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP也会拦截 - 云厂商安全组默认屏蔽 ICMP,此时
ping必然失败,但arping或 TCP 端口探测(如nc -z -w1 $ip 22)可能成功
所以「ping 不通」不等于「服务器宕机」,尤其在混合云或策略收紧的环境中,必须结合 ARP 或服务端口验证才敢下结论。

















