You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:00:52