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

编写Shell脚本提取指定时间戳日志遇日期解析错误求助

日志时间戳解析错误排查与修复

问题场景

编写Shell脚本提取指定时间戳范围的日志,日志时间戳格式为[17:02:04:308][01-03-2024],执行脚本时出现日期解析错误,终端报错如下:

./extract_logs.sh serverout.txt "[17:02:04:308][01-03-2024]" "[17:02:04:325][01-03-2024]"
date: invalid date ‘ 17:02:04:308  01-03-2024 ’
date: invalid date ‘ 17:02:04:325  01-03-2024 ’
date: invalid date ‘ 17:02:04:227  01-03-2024 ’
./extract_logs.sh: line 39: [: : integer expression expected
date: invalid date ‘ 17:02:04:303  01-03-2024 ’
./extract_logs.sh: line 39: [: : integer expression expected
date: invalid date ‘ 17:02:04:304  01-03-2024 ’
./extract_logs.sh: line 39: [: : integer expression expected
date: invalid date ‘ 17:02:04:308  01-03-2024 ’
./extract_logs.sh: line 39: [: : integer expression expected

原脚本代码

#!/bin/bash

# Function to convert timestamp to seconds since epoch
convert_to_seconds() {
    local timestamp=$1
    date -d "$timestamp" +%s
}

# Check if correct number of arguments are passed
if [ "$#" -ne 3 ]; then
    echo "Usage: $0 <log_file_name> <start_timestamp> <end_timestamp>"
    echo "Timestamps should be in the format '[HH:MM:SS:SSS][DD-MM-YYYY]'"
    exit 1
fi

log_file=$1
start_timestamp=$2
end_timestamp=$3

# Convert start and end timestamps to seconds since epoch
start_seconds=$(convert_to_seconds "$start_timestamp")
end_seconds=$(convert_to_seconds "$end_timestamp")

# Check if log file exists
if [ ! -f "$log_file" ]; then
    echo "File not found: $log_file"
    exit 1
fi

# Read the log file line by line
while IFS= read -r line; do
    # Extract the timestamp from the log line
    if [[ $line =~ (\[[0-9]{2}:[0-9]{2}:[0-9]{2}:[0-9]{3})\]\[([0-9]{2}-[0-9]{2}-[0-9]{4})\] ]]; then
        log_time="[${BASH_REMATCH[1]}][${BASH_REMATCH[2]}]"
        log_seconds=$(convert_to_seconds "$log_time")

        # Check if log time is within the specified range
        if [ "$log_seconds" -ge "$start_seconds" ] && [ "$log_seconds" -le "$end_seconds" ]; then
            echo "$line"
        fi
    fi
done < "$log_file"

问题根源

  1. 时间戳格式不兼容date命令:date -d无法识别带方括号的[HH:MM:SS:SSS][DD-MM-YYYY]格式,且拆分后的HH:MM:SS:SSS(毫秒用冒号分隔)也不符合date的解析规则;同时DD-MM-YYYY格式未明确指定,会被date误判为MM-DD-YYYY。
  2. 正则匹配后拼接错误:正则捕获的内容包含左方括号,拼接后的log_time仍带方括号,无法被date解析。
  3. 无错误处理机制:date解析失败时,log_seconds为空值,导致后续整数比较出现integer expression expected错误。

修复后的脚本

#!/bin/bash

# Function to convert timestamp to seconds since epoch
convert_to_seconds() {
    local timestamp=$1
    # 正则拆分时间(HH:MM:SS)和日期(DD-MM-YYYY)部分
    if [[ "$timestamp" =~ \[([0-9]{2}:[0-9]{2}:[0-9]{2}):[0-9]{3}\]\[([0-9]{2}-[0-9]{2}-[0-9]{4})\] ]]; then
        local time_part=${BASH_REMATCH[1]}
        local date_part=${BASH_REMATCH[2]}
        # 指定日期格式为DD-MM-YYYY,确保date正确解析
        date -d "$date_part $time_part" +%s
    else
        echo "Invalid timestamp format: $timestamp" >&2
        return 1
    fi
}

# 检查参数数量
if [ "$#" -ne 3 ]; then
    echo "Usage: $0 <log_file_name> <start_timestamp> <end_timestamp>"
    echo "Timestamps should be in the format '[HH:MM:SS:SSS][DD-MM-YYYY]'"
    exit 1
fi

log_file=$1
start_timestamp=$2
end_timestamp=$3

# 转换起始时间戳,失败则退出
start_seconds=$(convert_to_seconds "$start_timestamp")
if [ $? -ne 0 ]; then
    exit 1
fi

# 转换结束时间戳,失败则退出
end_seconds=$(convert_to_seconds "$end_timestamp")
if [ $? -ne 0 ]; then
    exit 1
fi

# 检查日志文件是否存在
if [ ! -f "$log_file" ]; then
    echo "File not found: $log_file"
    exit 1
fi

# 逐行读取日志并过滤
while IFS= read -r line; do
    # 直接捕获日志行中的时间和日期部分
    if [[ "$line" =~ \[([0-9]{2}:[0-9]{2}:[0-9]{2}):[0-9]{3}\]\[([0-9]{2}-[0-9]{2}-[0-9]{4})\] ]]; then
        local time_part=${BASH_REMATCH[1]}
        local date_part=${BASH_REMATCH[2]}
        # 转换时间戳并屏蔽错误输出
        log_seconds=$(date -d "$date_part $time_part" +%s 2>/dev/null)
        
        # 仅当转换成功时进行范围判断
        if [ -n "$log_seconds" ]; then
            if [ "$log_seconds" -ge "$start_seconds" ] && [ "$log_seconds" -le "$end_seconds" ]; then
                echo "$line"
            fi
        fi
    fi
done < "$log_file"

修复说明

  • 优化时间戳解析:直接用正则拆分出HH:MM:SS(忽略毫秒,因date +%s仅返回秒级时间戳)和DD-MM-YYYY,避免传递无效格式给date命令。
  • 明确日期解析规则:通过date -d "$date_part $time_part"明确指定日期格式为DD-MM-YYYY,消除locale差异导致的解析错误。
  • 增加错误处理:检查convert_to_seconds的执行结果,解析失败则直接退出;循环中判断log_seconds是否为空,避免整数比较错误。
  • 提升执行效率:循环内直接捕获时间和日期,无需重复调用转换函数,减少冗余操作。

内容的提问来源于stack exchange,提问作者Arav Stark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:42:31