Цикл не перебирает файл журнала в bash - PullRequest
0 голосов
/ 25 февраля 2019

Приветствую всех,

К сожалению, я должен попросить о помощи.

Я пытаюсь написать простой скрипт, отображающий время процедуры на основе файла журнала.Однако мой цикл не работает должным образом.

fun.sh

STARTPROCEDURES="START Search"
ENDPROCEDURES="END Search"

start() {
start="$(grep "$STARTPROCEDURES" s.log | cut -d ' ' -f2)"

hours="$(date -d $start '+%H')"
minutes="$(date -d $start '+%M')"
seconds="$(date -d $start '+%S')"
milliseconds=$(($(date -d $start +%N  | sed 's/^0*//')/1000000))

starttime=$(((hours * 360000000 + minutes * 60000 + seconds * 1000 + milliseconds)))

echo "Begins: " $starttime
}

end() {
end="$(grep "$ENDPROCEDURES" s.log | cut -d ' ' -f2)"

hours="$(date -d $end '+%H')"
minutes="$(date -d $end '+%M')"
seconds="$(date -d $end '+%S')"
milliseconds=$(($(date -d $end +%N  | sed 's/^0*//')/1000000))

endtime=$(((hours * 360000000 + minutes * 60000 + seconds * 1000 + milliseconds)))

echo "Ends: " $endtime
}

difference() {
echo "DIFFERENCE -----"

difference=$((endtime  - starttime))
echo "The difference is" $difference "milliseconds"
}

calculate() {
start
end
difference
}

while IFS= read -r line || [[ -n $line ]]; do
calculate
echo "-------"
done < s.log

s.log:

2019-02-22 06:27:06,857 INFO [ProcedureUtil] - (user1,14)  START Search
2019-02-22 06:27:06,939 INFO [ProcedureUtil] - (user1,14)  END Search
2019-02-22 07:28:16,088 INFO [ProcedureUtil] - (user1,67)  START Search
2019-02-22 07:28:16,121 INFO [ProcedureUtil] - (user1,67)  END Search

bash fun.sh

Хьюстон, у нас проблема.

вывод консоли:

date: extra operand ‘+%H’
Try 'date --help' for more information.
date: extra operand ‘+%M’
Try 'date --help' for more information.
date: extra operand ‘+%S’
Try 'date --help' for more information.
date: extra operand ‘+%N’
Try 'date --help' for more information.
fun.sh: line 21: /1000000: syntax error: operand expected (error token is "/1000000")

должен быть примерно таким

Begins:  2161626857
Ends:  2161626939
DIFFERENCE -----
The difference is 82 milliseconds
------
Begins:  216162343
Ends:  216162355
DIFFERENCE -----
The difference is 162 milliseconds

, если s.log:

2019-02-22 06:27:06,857 INFO [ProcedureUtil] - (user1,14)  START Search
2019-02-22 06:27:06,939 INFO [ProcedureUtil] - (user1,14)  END Search

вывод на консоль:

Begins:  2161626857
Ends:  2161626939
DIFFERENCE -----
The difference is 82 milliseconds
-------
Begins:  2161626857
Ends:  2161626939
DIFFERENCE -----
The difference is 82 milliseconds
-------

дважды на одно и то же, и это должно быть один раз.

Я буду очень изящен за помощь

Я рассматриваю случай: где s.log:

2019-02-22 06:27:06,857 INFO [ProcedureUtil] - (user1,14)  START Search
2019-02-22 06:27:06,939 INFO [ProcedureUtil] - (user1,14)  END Search
2019-02-22 07:28:16,088 INFO [ProcedureUtil] - (user1,67)  START Split
2019-02-22 07:28:16,121 INFO [ProcedureUtil] - (user1,67)  END Split
2019-02-22 07:28:16,088 INFO [ProcedureUtil] - (user1,67)  START Search
2019-02-22 07:28:16,121 INFO [ProcedureUtil] - (user1,67)  END Search
2019-02-25 20:59:59,999 INFO [ProcedureUtil] - (user1,17)  START Search
2019-02-25 02:59:59,999 INFO [ProcedureUtil] - (user1,18)  START Search

плохое решение:

COUNTER=0
while IFS= read -r line || [[ -n $line ]]; do
if [[ $line == *"START Search"* ]]; then
    start=$(time2millis "$line")
    echo "Begins: $start"

elif [[ $line == *"END Search"* ]]; then 
    end=$(time2millis "$line")
    echo "Ends: $end"

    # Assume every END has a preceding START
    difference "$start" "$end"
else
     COUNTER=$((COUNTER+1))
     echo "$COUNTER"
fi     
done < s.log

вывод консоли:

Begins: 23226857
Ends: 23226939
DIFFERENCE -----
The difference is 82 milliseconds
------
Begins: 26896088
Ends: 26896121
DIFFERENCE -----
The difference is 33 milliseconds
------
Begins: 75599999
Begins: 10799999

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Полное решение:

difference() {
    local diff=$(( $3 - $2 ))
    while (( diff < 0 )); do (( diff += 86400000 )); done
    printf "DIFFERENCE $1 -----\nThe difference is %d milliseconds\n------\n" "$diff"
}

# returns milliseconds since 1970-01-01 00:00:00 UTC
time2millis() {
    local epoch=$( date -d "$(echo "$1" | cut -d ' ' -f 1,2)" '+%s' )
    local millis=0
    [[ $1 =~ ,([0-9]+) ]] && millis=${BASH_REMATCH[1]}
    echo "$(( $epoch * 1000 + 10#$millis ))"
}

declare -A startTime startLine
while IFS= read -r line || [[ -n $line ]]; do
    read -a words <<<"$line"
    key=${words[5]}

    if [[ "${words[6]} ${words[7]}" == "START Search" ]]; then
        startLine[$key]=$line
        startTime[$key]=$(time2millis "$line")

    elif [[ "${words[6]} ${words[7]}" == "END Search" ]]; then
        if [[ -z ${startTime[$key]} ]]; then
            echo "END seen with no START: $line"
        else
            end=$(time2millis "$line")
            difference "$key" "${startTime[$key]}" "$end"
            unset startLine[$key] startTime[$key]
        fi
    fi
done < s.log

echo "Searches STARTed but not ENDed:"
printf "%s\n" "${startLine[@]}"

Учитывая ваши входные данные, это выводит

DIFFERENCE (user1,14) -----
The difference is 82 milliseconds
------
DIFFERENCE (user1,67) -----
The difference is 33 milliseconds
------
Searches STARTed but not ENDed:
2019-02-25 02:59:59,999 INFO [ProcedureUtil] - (user1,18)  START Search
2019-02-25 20:59:59,999 INFO [ProcedureUtil] - (user1,17)  START Search
0 голосов
/ 25 февраля 2019

Проблемы:

  • вы читаете файл построчно, но вы нигде не используете $line: вы копируете весь файл
  • поскольку этот вызов grep возвращает несколько совпадений, ваша переменная $start содержит символы новой строки
  • , поскольку вы не заключаете в кавычки переменную в вызове date, которая выглядит следующим образом

    date -d 06:27:06,857 07:28:16,088 '+%H'
    

    что явно слишком много аргументов на сегодняшний день

Большинство ошибок можно устранить, упрощая ваш код.Обратите внимание, что ваши функции start и end функционально идентичны.

difference() {
    local diff=$(( $2  - $1 ))
    printf 'DIFFERENCE -----\nThe difference is %d milliseconds\n------\n' "$diff"
}

time2millis() {
    local time=$(echo "$1" | cut -d ' ' -f 2)
    IFS=:, read -r hh mm ss nnn <<<"$time"
    # be aware of invalid octal numbers 08 and 09: 
    # each component of the time must be handled as a decimal number
    echo "$(( (((10#$hh) * 60 + 10#$mm) * 60 + 10#$ss) * 1000 + 10#$nnn ))"
}

while IFS= read -r line || [[ -n $line ]]; do
    if [[ $line == *"START Search"* ]]; then
        start=$(time2millis "$line")
        echo "Begins: $start"

    elif [[ $line == *"END Search"* ]]; then 
        end=$(time2millis "$line")
        echo "Ends: $end"

        # Assume every END has a preceding START
        difference "$start" "$end"
    fi
done < s.log

Дальнейшее развитие:

  1. Это не учитывает случай, когда END происходит на следующий день

    2019-02-28 23:59:59,999 blah blah START Search
    2019-03-01 00:00:00,001 blah blah END Search
    

    Вместо возвратас разницей в 2 мс, вы увидите разницу -86399998

  2. , для которой не учитывается переход на летнее время (если только в вашем журнале не записаны метки времени в формате UTC).

Я думаю, что эти проблемы можно решить с помощью date для анализа даты и времени:

time2millis() {
    local epoch=$( date -d "$(echo "$1" | cut -d ' ' -f 1,2)" '+%s' )
    local millis=0
    [[ $1 =~ ,([0-9]+) ]] && millis=${BASH_REMATCH[1]}
    echo "$(( $epoch * 1000 + 10#$millis ))"
}
...