Извлеките непредсказуемые данные, у которых есть собственная метка времени, в файле журнала с помощью сценария оболочки - PullRequest
0 голосов
/ 03 августа 2020

log.txt будет таким, как показано ниже, это данные идентификатора с собственной временной меткой (обнаружение_времени), которая будет постоянно обновляться в этом файле log.txt. Идентификационные данные будут непредсказуемым числом. Это может быть 0000-9999, и тот же идентификатор может снова появиться в log.txt.

Моя цель - отфильтровать идентификатор, который снова появляется в log.txt в течение 15 секунд c от его первое появление с использованием сценария оболочки. Может ли кто-нибудь помочь мне с этим?

ID = 4231
detection_time = 1595556730 
ID = 3661
detection_time = 1595556731
ID = 2654
detection_time = 1595556732
ID = 3661
detection_time = 1595556733

Чтобы быть более понятным, из log.txt выше, ID 3661 сначала появляется во время 1595556731, а затем снова появляется в 1595556733, что всего 2 se c после первое появление. Таким образом, он соответствует моему условию, которое требует, чтобы идентификатор снова появлялся в пределах 15se c. Я бы хотел, чтобы этот идентификатор 3661 был отфильтрован моим сценарием оболочки

Результатом после запуска сценария оболочки будет ID = 3661

Моя проблема в том, что я не знаю, как разрабатывать программы алгоритм в сценарии оболочки.

Вот что я пытаюсь использовать, используя переменные ID_new и ID_previous, но ID_previous=$(ID_new) detection_previous=$(detection_new) не работают

input="/tmp/log.txt"
ID_previous=""
detection_previous=""
while IFS= read -r line
do
    ID_new=$(echo "$line" | grep "ID =" | awk -F " " '{print $3}')
    echo $ID_new
    detection_new=$(echo "$line" | grep "detection_time =" | awk -F " " '{print $3}')
    echo $detection_new
    ID_previous=$(ID_new)
    detection_previous=$(detection_new)
done < "$input"

EDIT log.txt на самом деле данные в наборе содержат ID, detect_time, Age и Height. Извините, что не упомянул об этом в первую очередь

ID = 4231
detection_time = 1595556730 
Age = 25
Height = 182
ID = 3661
detection_time = 1595556731
Age = 24
Height = 182
ID = 2654
detection_time = 1595556732
Age = 22
Height = 184    
ID = 3661
detection_time = 1595556733
Age = 27
Height = 175
ID = 3852
detection_time = 1595556734
Age = 26
Height = 156
ID = 4231
detection_time = 1595556735 
Age = 24
Height = 184

Я пробовал решение Awk. результат: 4231 3661 2654 3852 4231, которые являются всеми идентификаторами в log.txt. Правильный вывод должен быть 4231 3661

Исходя из этого, я думаю Данные о возрасте и росте могут повлиять на решение Awk, потому что они вставлены между данными в фокусе, такими как ID и detect_time.

1 Ответ

1 голос
/ 05 августа 2020

Предполагая, что отметки времени в файле журнала монотонно увеличиваются, вам понадобится только один проход с Awk. Для каждого id отслеживайте время последнего сообщения (используйте ассоциативный массив t, где ключ - id, а значение - последняя отметка времени). Если вы снова увидите тот же id, а разница между отметками времени меньше 15, сообщите об этом.

Для хорошей оценки сохраните второй массив p из тех, которые мы уже сообщали, чтобы мы не сообщайте о них дважды.

awk '/^ID = / { id=$3; next }
    # Skip if this line is neither ID nor detection_time
    !/^detection_time = / { next }
    (id in t) && (t[id] >= $3-15) && !(p[id]) { print id; ++p[id]; next }
    { t[id] = $3 }' /tmp/log.txt

Если вы действительно настаиваете на том, чтобы сделать это изначально в Bash, я бы реорганизовал вашу попытку до

declare -A dtime printed
while read -r field _ value
do
    case $field in
     ID) id=$value;;
     detection_time)
      if [[ dtime["$id"] -ge $((value - 15)) ]]; then
          [[ -v printed["$id"] ]] || echo "$id"
          printed["$id"]=1
      fi
      dtime["$id"]=$value ;;
    esac
done < /tmp/log.txt

Обратите внимание, как read -r может легко разделить строку на пробелы так же хорошо, как Awk, если вы знаете, сколько полей вы можете ожидать. Но while read -r обычно на порядок медленнее, чем Awk, и вы должны согласиться, что попытка Awk более лаконична и элегантна, а также переносима на старые системы.

(Были представлены ассоциативные массивы в Bash 4.)

По касательной все, что выглядит как grep 'x' | awk '{ y }', может быть преобразовано в awk '/x/ { y }'; см. также бесполезное использование grep.

Также обратите внимание, что $(foo) пытается запустить foo как команду. Чтобы просто сослаться на значение переменной foo, используйте синтаксис $foo (или, необязательно, ${foo}, но фигурные скобки здесь не добавляют значения). Обычно вам нужно заключить расширение "$foo" в двойные кавычки; см. также Когда следует заключать в кавычки переменную оболочки

Ваш сценарий запомнит только одно предыдущее событие; ассоциативный массив позволяет нам запоминать все ID значений, которые мы видели ранее (пока у нас не закончится память).

Ничто не мешает нам использовать удобочитаемые имена переменных в Awk; не стесняйтесь заменять printed на p и dtime на t, чтобы иметь полный паритет с альтернативой Bash.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...