Существенная проблема с логикой c кода заключается в том, что для сравнения дат используется сравнение строк. В сравнении строк Apr 17
меньше Apr 2
и Feb 1
меньше Jan 1
.
Вместо этого шаблон в оболочках POSIX должен преобразовывать дату в секунды, начиная с 1970-01-01 00:00:00 UT C, также известный как «эпоха».
Для команды date
укажите время в формате секунд, чтобы установить FORMAT
в +%s
, например, date +%s
.
В ksh
есть спецификатор формата printf
, T
, для преобразования строки, такой как строка, считываемая из файла журнала, в число секунд с начала эпохи. См. https://www.unix.com/302701867-post4.html?s=860f6c21431fa69ef9e083161f93739d
Вот ваш сценарий, переписанный для устранения ошибки logi c путем преобразования сравнений в секунды:
#!/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 такую специфическую проблему, c, то, вероятно, не будет представлять большого интереса для других, поэтому может потребоваться некоторое время, чтобы получить какой-либо значимый ответ.
Опция трассировки basi c равна -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 ))
k sh, появится предупреждение:
/tmp/bug.ksh: warning: line 14: variable expansion makes arithmetic evaluation less efficient
, потому что вместо этого предпочтительнее будет более эффективный (( line_secs > start_secs ))
, добавив дополнительную подстановку с помощью $
, которую вы увидите значения сравниваются в след. И это может помочь вам выяснить, какая часть выходит из строя.
Если вы уже знали об этом и попробовали это, то я думаю, что вы получите больше ответов, если перейдете в StackOverflow с трассировкой, как показано выше, а затем вопрос немного сузился до «почему это сравнение не удается?» и вы можете получить больше ответов быстрее.
Наконец, я упомяну, что я написал отладчики для современных ksh93
новее, чем 2014-12-24, zsh
и bash
. Однако, когда я попробовал приведенный выше пример на kshdb
, это не удалось, и я не уверен, почему.