1. 当脚本输出"乱成一锅粥"时
在日常运维和开发中,我们经常会遇到这样的场景:精心编写的Bash脚本明明功能正常,但输出结果却像超市小票般杂乱无章。某次我调试一个服务器监控脚本时,就遇到了这样的尴尬——关键指标数据与描述文字挤作一团,活像早高峰的地铁车厢。这种"功能正确但输出辣眼睛"的情况,正是本文要解决的核心问题。
2. 四大核心调整手法
2.1 printf:格式化输出界的瑞士军刀
#!/bin/bash
# 定义三个监控指标
cpu_usage="25.5%"
mem_usage="1.8GB"
disk_usage="75%"
# 使用printf进行对齐格式化
printf "%-15s | %-10s | %-10s\n" "CPU使用率" "内存用量" "磁盘占用"
printf "%'-45s\n" "" # 分隔线
printf "%-15s | %-10s | %-10s\n" "$cpu_usage" "$mem_usage" "$disk_usage"
# 输出效果:
# CPU使用率 | 内存用量 | 磁盘占用
# ---------------------------------------------
# 25.5% | 1.8GB | 75%
这里的%-15s
表示左对齐且占位15字符,管道符|
作为视觉分隔,百分号格式适用于数值展示。注意数字与单位之间保留空格,避免视觉拥挤。
2.2 awk:文本处理的多面手
#!/bin/bash
# 原始日志格式
log_data="2023-08-01 14:30:22,ERROR,Disk full,Server-01"
# 使用awk重新编排格式
echo "$log_data" | awk -F',' '{
printf "[%s] %s - %s (主机: %s)\n", $2, $1, $3, $4
}'
# 输出效果:
# [ERROR] 2023-08-01 14:30:22 - Disk full (主机: Server-01)
-F','
指定逗号分隔,字段重组时注意时间戳前置更符合阅读习惯,状态码用方括号突出显示。建议将字段变量$1
等替换为有意义的变量名提升可读性。
2.3 column:自动对齐的排版神器
#!/bin/bash
# 杂乱的服务状态数据
services=(
"nginx running 80/tcp"
"mysql active 3306/tcp"
"redis listening 6379/tcp"
)
# 格式化输出
printf "%s\n" "${services[@]}" | column -t -s ' '
# 输出效果:
# nginx running 80/tcp
# mysql active 3306/tcp
# redis listening 6379/tcp
-t
参数启用自动对齐,-s ' '
指定空格分隔符。注意原始数据中的空格数量不影响最终效果,适合处理参差不齐的原始数据。建议配合-o
参数设置自定义分隔符。
2.4 色彩魔法:让输出会说话
#!/bin/bash
# 定义颜色代码
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # 重置颜色
# 带颜色的状态显示
check_service() {
if systemctl is-active --quiet $1; then
echo -e "${GREEN}[✓]${NC} $1 运行正常"
else
echo -e "${RED}[×]${NC} $1 服务异常"
fi
}
check_service nginx
check_service mysql
# 输出示例:
# [✓] nginx 运行正常
# [×] mysql 服务异常
使用\033
转义序列实现跨终端兼容,注意颜色代码必须用-e
参数启用转义。建议将颜色变量集中定义,避免代码中散落魔法数值。
3. 关联技术:重定向
#!/bin/bash
# 将格式化后的输出同时显示并保存到文件
format_output() {
echo "====== 系统状态报告 ======"
date "+%Y-%m-%d %H:%M:%S"
free -h | awk '/Mem/{print "内存使用量: "$3"/"$2}'
}
# 使用tee命令分流输出
format_output | tee /var/log/system_report.log | sed 's/^/[实时监控] /'
# 输出示例:
# [实时监控] ====== 系统状态报告 ======
# [实时监控] 2023-08-01 15:00:00
# [实时监控] 内存使用量: 1.8G/3.7G
tee
命令如同三通水管,既保留原始流又创建副本。配合sed
添加前缀,实现动态标记。注意管道组合顺序影响处理逻辑。
4. 实战,日志分析报告生成
#!/bin/bash
# 分析nginx访问日志
analyze_access_log() {
log_file="/var/log/nginx/access.log"
echo "====== 访问统计报告 ======"
echo "统计时间: $(date '+%F %T')"
# 状态码统计
echo -e "\n[状态码分布]"
awk '{print $9}' $log_file | sort | uniq -c | sort -nr | awk '{
printf "状态码 %s: %s 次\n", $2, $1
}'
# 流量Top10 IP
echo -e "\n[流量TOP10]"
awk '{ips[$1]+=$10} END {
for(ip in ips) printf "%15s %s\n", ip, ips[ip]
}' $log_file | sort -k2 -nr | head -10 | column -t
}
analyze_access_log
该脚本演示了多级数据处理:状态码聚合使用uniq -c
计数,流量统计通过关联数组累加,最终通过管道组合实现排序和格式化输出。
5. 技术方案选型指南
5.1 各方法优缺点对比
printf
优势:内置命令、精确控制
不足:字段宽度需预先计算awk
优势:数据处理能力强
不足:语法相对复杂column
优势:自动对齐
不足:依赖额外软件包颜色输出
优势:直观醒目
不足:可能影响日志分析
5.2 性能考量
在循环处理万行数据时,column
的效率比printf
低约40%。建议大数据量场景采用awk原生格式化。
6. 避坑指南
- 中文字符对齐请使用
LC_ALL=C
环境变量 - 颜色代码在重定向到文件时需添加
--color=always
参数 - 处理CSV数据时注意转义逗号
- 定期检查
stty
大小变化对终端布局的影响
7. 总结与展望
掌握输出格式化如同为脚本配备智能排版系统。未来可结合jq处理JSON数据,或使用dialog创建交互界面。记住:好的输出格式如同得体的衣着,让脚本价值倍增。