Bash脚本如何实现首列值满足条件时输出对应第二列内容
问题根源
你当前代码重复输出的核心原因是把计数和IP拆成了两个完全独立的数据集:
$i变量存储的是排序后前5个IP的完整列表,没有和单个计数做绑定- 循环遍历计数时,只要某一个计数满足阈值,就会把整个IP列表全量打印一次
最终有多少个符合阈值的计数,就会重复打印多少次完整IP列表,完全没有实现计数和对应IP的匹配。
另外原代码还有两个隐性问题:
- 赋值
c的命令末尾用了>> $CFILE追加写入,c变量本身拿不到任何值,且如果$CFILE残留旧内容会导致统计结果错误 - 重复执行了多轮相同的排序、去重逻辑,性能浪费严重
最优实现(无需数组)
不需要拆分计数、IP为两个独立变量,也不需要额外存临时文件,直接在统计流程里用awk做逐行判断即可,逻辑最简单也最不容易出错:
# 可自行修改阈值100为你需要的数值 sed '/^$/d' "$IPS" | sort -rn | uniq -c | sort -rn | head -5 | awk '$1 > 100 {print $2}'
逻辑说明:uniq -c输出的本身就是「计数 IP」的两列结构,awk逐行处理时直接判断第一列计数值是否满足阈值,满足就打印当前行对应的第二列IP,天然做了一一绑定,不会出现重复、错位问题。
数组实现方案
如果你确实想用shell数组实现计数和IP的绑定,可参考下面写法,通过相同索引关联计数和对应IP:
# 定义阈值 threshold=100 # 声明两个数组分别存计数和IP,索引一一对应 declare -a count_list ip_list index=0 # 逐行读取统计结果,写入对应数组 while read -r cnt ip; do count_list[$index]=$cnt ip_list[$index]=$ip ((index++)) done < <(sed '/^$/d' "$IPS" | sort -rn | uniq -c | sort -rn | head -5) # 遍历数组索引,计数满足阈值时输出同索引的IP for i in "${!count_list[@]}"; do if (( count_list[i] > threshold )); then echo "${ip_list[i]}" fi done
注意:不建议用
for 变量 in $(cat 文件)的写法遍历内容,遇到空格、特殊转义字符时容易出现解析错误,用while read逐行读取的兼容性更好。
内容的提问来源于stack exchange,提问作者include
相关产品推荐
相关产品推荐

