编写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"
问题根源
- 时间戳格式不兼容
date命令:date -d无法识别带方括号的[HH:MM:SS:SSS][DD-MM-YYYY]格式,且拆分后的HH:MM:SS:SSS(毫秒用冒号分隔)也不符合date的解析规则;同时DD-MM-YYYY格式未明确指定,会被date误判为MM-DD-YYYY。 - 正则匹配后拼接错误:正则捕获的内容包含左方括号,拼接后的
log_time仍带方括号,无法被date解析。 - 无错误处理机制:
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
相关产品推荐
相关产品推荐

