Ниже приведен сценарий. Когда я пытаюсь его выполнить, он говорит, что произошла ошибка при анализе даты.
[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.
Обходной путь — преобразовать даты во что-то разумное; но поскольку это всего лишь числа, вам не нужно преобразовывать значение в секунды — просто выполните простое сравнение строк после изменения порядка полей.
#!/bin/bash
# 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
# Check if log file exists
if [ ! -f "$log_file" ]; then
echo "File not found: $log_file"
exit 1
fi
awk -v start = "$start_timestamp" -v end = "$end_timestamp" '
function parsedate(date) {
split(date, a, /[]:[-]+/)
return a[8] "-" a[7] "-" a[6] "T" a[2] ":" a[3] ":" a[4] "." a[5]
}
BEGIN {
st = parsedate(start)
et = parsedate(end)
}
((p = parsedate($0)) >= st) && (p <= et)' "$1"
Я переработал основную логику на Awk, поскольку она значительно более лаконична, чем эквивалентный код Bash.
Демо: https://ideone.com/GOgdoP
Кстати, обратите внимание, что существует несколько версий date. Судя по всему, вы используете Linux, который использует GNU date (который поддерживает, например, опцию -d для указания даты). Например, BSD/MacOS у вас есть разные опции (включая возможность указать, как именно преобразовать строку в каком-то дурацком формате в дату, но со множеством других странностей).
tripleee прав — у вас не очень хорошая структура временных меток.
Если вы можете это контролировать, исправьте это.
Если возможно, используйте YEAR-MO-DY HH::MM::SS, как в
$: date +'%F %T'
2024-06-11 08:02:06
Тем не менее, это всего лишь вопрос правильного анализа ваших данных.
$: [[ $timestamp =~ ^\[([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}):[[:digit:]]{3}\]\[([[:digit:]]{2})-([[:digit:]]{2})-([[:digit:]]{4})\] ]] && printf "%s\n" "${BASH_REMATCH[@]}" || echo nomatch
[17:02:04:308][01-03-2024]
17:02:04
01
03
2024
$: date -d "${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]} ${BASH_REMATCH[1]}" +%s 1709334124
Итак, чтобы переписать существующую функцию:
$: convert_to_seconds() {
if [[ $1 =~ ^\[([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}):[[:digit:]]{3}\]\[([[:digit:]]{2})-([[:digit:]]{2})-([[:digit:]]{4})\]$ ]]
then date -d "${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]} ${BASH_REMATCH[1]}" +%s
else echo "Invalid timestamp: '$1'" >&2
return 1
fi
}
$: convert_to_seconds $timestamp
1709334124
$: convert_to_seconds foo
Invalid timestamp: 'foo'
Немного прикрасился -
convert_to_seconds() {
local timestamp = "$1" format
local pattern=$'^\[([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}):[[:digit:]]{3}\]' # the time portion
pattern+=$'\[([[:digit:]]{2})-([[:digit:]]{2})-([[:digit:]]{4})\]$' # the date portion
if [[ $1 =~ $pattern ]]
then format = "${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]} ${BASH_REMATCH[1]}" # parsed
date -d "${BASH_REMATCH[4]}-${BASH_REMATCH[3]}-${BASH_REMATCH[2]} ${BASH_REMATCH[1]}" +%s;
else echo "Invalid timestamp: '$1'" >&2
return 1
fi
}
Трипли тоже прав, что awk будет для этого намного эффективнее.
к сожалению, у меня нет полномочий изменять формат метки времени.
Почему ваш формат даты вообще безумен?