代码逻辑的根本问题是使用字符串比较来比较日期。在字符串比较中,Apr 17 小于 Apr 2 并且 Feb 1 小于 Jan 1。
相反,POSIX shell 中的模式是将日期转换为自 1970-01-01 00:00:00 UTC 以来的秒数,也称为“纪元”。
对于date 命令,以这种秒格式给出时间的方法是将FORMAT 设置为+%s,例如date +%s。
在ksh 中有一个printf 格式说明符T,用于将字符串(例如从日志文件中读取的行)转换为自纪元以来的秒数。见https://www.unix.com/302701867-post4.html?s=860f6c21431fa69ef9e083161f93739d
这是您重写的脚本,通过将比较转换为秒来解决逻辑错误:
#!/bin/ksh
ERROR_LOG=/tmp/error.log
FILTERED_ERROR_LOG=/tmp/text
now_secs=$(date "+%s")
start_secs=$(date --date="-30000 min" +%s)
while read line; do
# Below stderr is redirected since I can't figure out how to get just the first part
# of the date parsed skipping the other stuff after that.
# Even though there is warning printed, the time comes out parsed correctly
line_secs=$(printf "%(%#)T" "$line" 2>/dev/null)
if (( $line_secs > $start_secs && line_secs < now_secs || line_secs == now_secs )); then
echo $line | egrep -wi '[Cc]ritical' >> $FILTERED_ERROR_LOG
fi
done < $ERROR_LOG
一些附加说明。
您似乎更广泛地可能希望了解此类调试此类问题。如您所见,在 StackOverflow 上询问这样一个非常具体的问题可能不会引起其他人的兴趣,因此可能需要一段时间才能得到任何有意义的响应。
基本跟踪选项是-x。让我们在上面的脚本上运行它:
ksh -x /tmp/bug.ksh
+ ERROR_LOG=/tmp/error.log
+ FILTERED_ERROR_LOG=/tmp/text
+ date +%s
+ now_secs=1587473181
+ date '--date=-30000 min' +%s
+ start_secs=1585673181
+ 0< /tmp/error.log
+ read line
+ printf '%(%#)T' 'Apr 7 05:58:05 ip-172-31-19-169 kernel: BIOS-provided physical RAM map: critical'
+ 2> /dev/null
+ line_secs=1586253485
+ (( 1586253485 > 1585673181 && line_secs < now_secs || line_secs == now_secs ))
+ egrep -wi '[Cc]ritical'
+ echo Apr 7 05:58:05 ip-172-31-19-169 kernel: BIOS-provided physical RAM map: critical
+ 1>> /tmp/text
+ read line
+ printf '%(%#)T' 'Apr 7 09:21:12 ip-172-31-19-169 kernel: BIOS-provided physical RAM map: critical'
+ 2> /dev/null
+ line_secs=1586265672
+ (( 1586265672 > 1585673181 && line_secs < now_secs || line_secs == now_secs ))
+ egrep -wi '[Cc]ritical'
+ echo Apr 7 09:21:12 ip-172-31-19-169 kernel: BIOS-provided physical RAM map: critical
+ 1>> /tmp/text
+ read line
+ printf '%(%#)T' 'Apr 7 13:05:57 ip-172-31-19-169 kernel: BIOS-provided physical RAM map: critical'
+ 2> /dev/null
+ line_secs=1586279157
+ (( 1586279157 > 1585673181 && line_secs < now_secs || line_secs == now_secs ))
+ egrep -wi '[Cc]ritical'
+ echo Apr 7 13:05:57 ip-172-31-19-169 kernel: BIOS-provided physical RAM map: critical
+ 1>> /tmp/text
+ read line
我以几种方式更改了您的代码,以便更容易调试和查看问题。将您想做的事情附加到日志文件中,作为if 中的单独语句而不是&& 条件的一部分,在类似上面的跟踪中,您会看到它显示为单独的线。特别是当你看到:
+ egrep -wi '[Cc]ritical'
+ echo Apr 7 05:58:05 ip-172-31-19-169 kernel: BIOS-provided physical RAM map: critical
我们知道测试成功了。如果您想知道时间测试是否因为第一部分(时间不够新)或第二部分(时间太新)或与第三部分不匹配(现在时间)而失败,那么将这些放入他们自己的if 或else 将允许跟踪显示。
但是我已经做了一些其他的事情来简化调试。虽然
使用(( $line_secs > $start_secs )) ksh 之类的构造会发出警告:
/tmp/bug.ksh: warning: line 14: variable expansion makes arithmetic evaluation less efficient
因为它更喜欢更有效的(( line_secs > start_secs )),所以通过使用$ 添加额外的替换,您将在跟踪中看到比较的值。这可能会帮助您找出哪个部分失败了。
如果您已经知道这一点并尝试过,那么我认为如果您带着如上所示的跟踪来到 StackOverflow,您会得到更多的回应,然后问题会缩小到“为什么这个比较失败? "并且您可能会更快地获得更多回复。
最后,我要提到的是,我已经为比 2014-12-24、zsh 和 bash 更新的现代 ksh93 编写了调试器。但是,当我在 kshdb 上尝试上述示例时,它失败了,我不知道为什么。