如何将utmpdump多行日志转为独立JSON文件并排查分割异常
问题
我当前通过bash脚本每小时使用utmpdump工具导出Linux认证日志,脚本如下:
dateLastHour=$(date +"%a %b %d %H:" -d '1 hour ago') dateNow=$(date +"%a %b %d %H:") utmpdump /var/log/wtmp* | awk "/$dateLastHour/,/$dateNow/"
我需要把上述结果按行分割成单个认证日志,再将每个事件转换成独立JSON文件,导出到外部syslog收集器用于分析和长期存储。
测试输出结果示例:
[7] [08579] [ts/0] [egecko] [pts/0 ] [10.0.2.6 ] [1.1.1.1 ] [Fri Nov 04 23:40:29 2022 EDT] [8] [08579] [ ] [ ] [pts/0 ] [ ] [0.0.0.0 ] [Fri Nov 04 23:55:16 2022 EDT] [2] [00000] [~~ ] [reboot ] [~ ] [3.10.0-1160.80.1.el7.x86_64] [0.0.0.0 ] [Sat Dec 03 12:28:05 2022 EST] [5] [00811] [tty1] [ ] [tty1 ] [ ] [0.0.0.0 ] [Sat Dec 03 12:28:12 2022 EST] [6] [00811] [tty1] [LOGIN ] [tty1 ] [ ] [0.0.0.0 ] [Sat Dec 03 12:28:12 2022 EST] [1] [00051] [~~ ] [runlevel] [~ ] [3.10.0-1160.80.1.el7.x86_64] [0.0.0.0 ] [Sat Dec 03 12:28:58 2022 EST] [7] [02118] [ts/0] [egecko] [pts/0 ] [1.1.1.1 ] [1.1.1.1 ] [Sat Dec 03 12:51:22 2022 EST]
我尝试用SED去除多余空格,再用IFS按换行分割为数组,但执行echo $array时只返回第一行,求指导。
用到的代码:
utmpResults=$(echo "$utmpResults" | sed 's/ */ /g') IFS="\n" read -a array <<< "$utmpResults" echo $array
解决方案
1. 修复数组读取问题
你的数组读取失败是因为两个关键问题:
IFS="\n"里的换行符需要用ANSI-C转义写法IFS=$'\n'才能被bash识别read -a默认只读取一行,需要加上-d ''让它读取到输入结束,同时用-r关闭反斜杠转义避免数据失真
修改后的数组读取代码:
utmpResults=$(utmpdump /var/log/wtmp* | awk "/$dateLastHour/,/$dateNow/") # 去除多余连续空格 utmpResults=$(echo "$utmpResults" | sed 's/ */ /g') # 正确读取所有行到数组 IFS=$'\n' read -r -d '' -a array <<< "$utmpResults" # 验证数组内容,遍历输出每一行 for line in "${array[@]}"; do echo "$line" done
2. 直接转换为JSON并导出到syslog
不需要先存入数组,用awk可以一次性完成过滤、格式处理和JSON转换,效率更高:
dateLastHour=$(date +"%a %b %d %H:" -d '1 hour ago') dateNow=$(date +"%a %b %d %H:") utmpdump /var/log/wtmp* | awk -v start="$dateLastHour" -v end="$dateNow" ' # 匹配目标时间范围的行 $0 ~ start, $0 ~ end { # 移除所有方括号和多余空格 gsub(/\[|\]/, "", $0) gsub(/ */, " ", $0) # 分割字段到数组 split($0, fields, " ") # 定义字段名对应顺序 keys[1] = "type" keys[2] = "pid" keys[3] = "device" keys[4] = "user" keys[5] = "terminal" keys[6] = "remote_host" keys[7] = "ip" # 拼接时间字段(包含空格,需单独处理) time_str = fields[8]" "fields[9]" "fields[10]" "fields[11]" "fields[12] # 构建JSON字符串 printf "{" printf "\"%s\":\"%s\",", keys[1], fields[1] printf "\"%s\":\"%s\",", keys[2], fields[2] printf "\"%s\":\"%s\",", keys[3], fields[3] printf "\"%s\":\"%s\",", keys[4], fields[4] printf "\"%s\":\"%s\",", keys[5], fields[5] printf "\"%s\":\"%s\",", keys[6], fields[6] printf "\"%s\":\"%s\",", keys[7], fields[7] printf "\"timestamp\":\"%s\"", time_str printf "}\n" }' | while read -r json; do # 发送到外部syslog收集器,替换为你的收集器地址和端口 logger -n 192.168.1.100 -P 514 -t "utmp_events" "$json" # 如果需要保存为独立JSON文件,取消下面注释 # echo "$json" > "/tmp/utmp_event_$(date +%Y%m%d%H%M%S_%N).json" done
说明
awk部分直接处理每行数据,自动过滤时间范围,清理格式后映射为标准JSON键值对- 时间字段因包含空格单独拼接,避免分割错误
while read循环负责将每个JSON条目发送到syslog收集器,也可生成唯一命名的JSON文件留存
内容的提问来源于stack exchange,提问作者Elaborate Gecko
相关产品推荐
相关产品推荐

