Bash脚本提取日志指定时间戳区间行的运行报错修复
Bash日志按时间范围过滤脚本报错修复方案
问题表现
- 执行命令
./test.sh -t 22/06/24,17:58:00-22/06/24,18:11:59时抛出错误:./test.sh: line 43: [: -gt: unary operator expected - 目标日志行首固定为
YY/MM/DD hh:mm:ss格式时间戳,后续为具体日志内容 - 原有脚本逻辑为将起止时间、日志行时间统一转换为Unix时间戳后做大小比对,实际运行无法返回预期过滤结果
报错根因
该错误是Bash数值比较场景的典型语法错误,触发原因是-gt/-ge/-le这类比较运算符的左侧或右侧操作数为空,常见诱因:
- 解析
-t传入的时间范围参数时,横杠、逗号分隔的字符串拆分逻辑错误,传入时间转换命令的字符串格式不符合要求 - 调用
date命令转时间戳时未指定匹配的输入格式,解析失败返回空值 - 提取日志行首时间戳时未做格式校验,空行、格式不匹配的日志行提取出的字符串无法被
date解析,返回空值 - 数值比较语句中的变量未加双引号包裹,空值会被Bash解析为缺少操作数
修复后可直接运行的脚本
#!/bin/bash # 按时间范围过滤日志脚本 LOG_FILE="/path/to/your/target.log" # 替换为实际日志文件路径 while getopts "t:" opt; do case $opt in t) time_range="$OPTARG" # 拆分起止时间字符串 start_raw="${time_range%-*}" end_raw="${time_range#*-}" # 将参数中的逗号替换为空格,对齐日志原生时间格式 start_fmt="${start_raw//,/ }" end_fmt="${end_raw//,/ }" # 转换为Unix时间戳,错误输出重定向丢弃 start_ts=$(date -d "$start_fmt" +%s 2>/dev/null) end_ts=$(date -d "$end_fmt" +%s 2>/dev/null) # 校验时间参数合法性 if [ -z "$start_ts" ] || [ -z "$end_ts" ]; then echo "时间参数格式错误,合法格式:YY/MM/DD,hh:mm:ss-YY/MM/DD,hh:mm:ss" exit 1 fi ;; *) echo "无效参数,使用方式:$0 -t 开始时间-结束时间" exit 1 ;; esac done # 逐行读取日志做匹配 while IFS= read -r line; do # 提取行首15位固定长度的时间戳 log_time_str="${line:0:15}" # 转换日志时间戳,转换失败(格式不匹配行)直接跳过 log_ts=$(date -d "$log_time_str" +%s 2>/dev/null) [ -z "$log_ts" ] && continue # 时间范围匹配,变量全部加双引号避免语法错误 if [ "$log_ts" -ge "$start_ts" ] && [ "$log_ts" -le "$end_ts" ]; then echo "$line" fi done < "$LOG_FILE"
关键修复点
- 所有
[ ]比较语句中的变量统一加双引号包裹,从语法层面避免空值触发的操作数缺失错误 - 时间参数拆分后统一替换逗号为空格,和日志原生时间格式对齐,降低
date解析失败概率 - 所有时间戳转换步骤后增加空值校验,非法参数直接报错退出,非法格式日志行直接跳过,不流入比较逻辑
- 逐行读取日志使用
IFS= read -r写法,避免行首尾空格、特殊字符被Bash自动转义导致内容丢失
兼容说明
如果在MacOS系统运行,系统自带date命令参数和GNU date不兼容,将脚本中所有时间转换语句替换为对应BSD date写法即可:date -j -f "%y/%m/%d %H:%M:%S" "$待转换时间字符串" +%s
内容的提问来源于stack exchange,提问作者aden
相关产品推荐
相关产品推荐

