Shell脚本调用vnstat获取带宽数据无输出及输出格式异常问题求助
Shell脚本调用vnstat获取带宽数据无输出及输出格式异常问题求助
我完全理解你作为非Shell脚本开发者,碰到这种数据提取和格式转换的问题有多头疼!咱们先拆解你原脚本里的问题,再给你一个更可靠的修复版本。
原脚本的核心问题
- 完全依赖固定行号和字段位置:vnstat的输出行数会随着显示的小时数变化,固定用
tail -n2、tail -n9或者$11提取字段,很容易因为输出格式变化(比如终端宽度、vnstat版本更新)拿到空值或者错误数据。 - 数值处理逻辑错误:如果你的系统是欧洲 locale,vnstat的数值会用逗号做小数点(比如
1,23),原脚本把逗号分割的两部分直接拼接成123,完全破坏了浮点数格式。 - 单位提取不可靠:从固定行里抠单位的方式太脆弱,一旦输出结构变了就彻底失效。
- 没处理空值情况:如果vnstat还没生成统计数据,你的脚本会拿着空值继续计算,结果自然异常。
- 比特/字节转换遗漏:vnstat的平均速率单位通常是
kbit/s这类比特单位,原脚本直接乘以1024,没考虑1字节=8比特的转换,结果会差8倍!
修复后的脚本
这个版本更健壮,能适配大多数vnstat输出场景,还处理了空值和格式问题:
# 提取最新小时的统计行,排除掉最后一行的"estimated"预估数据 latest_hour_line=$(vnstat -h | grep -v "estimated" | tail -n1) # 从该行提取速率数值和单位:倒数第二个字段是数值,最后一个是单位 # 把数值里的逗号(欧洲小数点)替换成点,确保bc能识别为浮点数 rate_value=$(echo "$latest_hour_line" | awk '{gsub(/,/, ".", $(NF-1)); print $(NF-1)}') rate_unit=$(echo "$latest_hour_line" | awk '{print $NF}') # 检查是否成功提取到数值,空值直接报错退出 if [ -z "$rate_value" ]; then echo "错误:无法获取vnstat带宽数据,请检查vnstat是否已启动并生成统计" exit 1 fi # 将速率转换为每秒字节数(注意区分比特和字节单位) case "$rate_unit" in kbit/s) # kbit/s转字节:1kbit = 1024比特,1字节=8比特 bandwidth_out_number_Byte=$(echo "scale=2; $rate_value * 1024 / 8" | bc) ;; Mbit/s) bandwidth_out_number_Byte=$(echo "scale=2; $rate_value * 1024 * 1024 / 8" | bc) ;; Gbit/s) bandwidth_out_number_Byte=$(echo "scale=2; $rate_value * 1024 * 1024 * 1024 / 8" | bc) ;; KiB/s) bandwidth_out_number_Byte=$(echo "scale=2; $rate_value * 1024" | bc) ;; MiB/s) bandwidth_out_number_Byte=$(echo "scale=2; $rate_value * 1024 * 1024" | bc) ;; GiB/s) bandwidth_out_number_Byte=$(echo "scale=2; $rate_value * 1024 * 1024 * 1024" | bc) ;; *) echo "错误:不支持的单位 $rate_unit" exit 1 ;; esac # 输出最终结果 echo "转换后的每秒带宽字节数:$bandwidth_out_number_Byte"
脚本说明
- 可靠的行提取:用
grep -v "estimated"排除预估行,再取最后一行,不管vnstat显示多少小时,都能拿到最新的统计数据。 - 自适应字段提取:用
$NF(最后一个字段)和$(NF-1)(倒数第二个字段)提取单位和数值,不依赖固定字段序号,适配不同输出格式。 - 数值格式修复:自动把逗号小数点转成点,确保后续计算能得到正确的浮点数。
- 空值检查:提前判断是否提取到数据,避免无效计算。
- 正确的单位转换:区分比特和字节单位,转换逻辑符合标准,不会出现数值偏差。
备注:内容来源于stack exchange,提问作者islam
相关产品推荐
相关产品推荐

