Below is the script. When I try to execute it, it says there is an error parsing the date.
[17:02:04:308][01-03-2024]
<-- This is the structure of the timestamp in my log file. The error in the terminal:
./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
The code:
#!/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"
The simple explanation is that date stamps in your crazy format are not acceptable to date
.
A workaround is to convert the dates to something sane; but since these are just numbers, you don't really need to convert the value to seconds -- just do a simple string comparison after reordering the fields.
#!/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"
I refactored the main logic to Awk as that is significantly more succinct than the equivalent Bash code.
Demo: https://ideone.com/GOgdoP
Tangentially, perhaps note also that there are multiple versions of date
. You are apparently on Linux, which uses GNU date
(which supports e.g. the -d
option for specifying a date). On e.g. BSD / MacOS you have different options (including an option to specify how exactly to convert a string in some wacky format to a date, but with many other oddities).