텍스트 파일에서 통계 인쇄

텍스트 파일에서 통계 인쇄

아래와 같은 텍스트 파일(events.dat)이 있습니다(발췌된 부분만 표시됨).

RepID12 01/01/2010 20:56:00 S10
RepID12 01/01/2010 20:56:00 S03
RepID20 01/01/2010 20:56:00 S17
RepID33 01/01/2010 20:56:00 S02
RepID33 01/01/2010 20:56:00 S18
RepID38 01/01/2010 20:56:00 S11
RepID39 01/01/2010 20:56:00 S20
RepID26 02/01/2010 01:39:00 S20
RepID29 02/01/2010 01:39:00 S16
RepID29 02/01/2010 01:39:00 S03
RepID22 02/01/2010 01:39:09 S01
RepID26 02/01/2010 01:39:09 S02
RepID40 02/01/2010 01:39:18 S02
RepID38 02/01/2010 01:39:09 S05
RepID31 02/01/2010 01:39:09 S06
RepID31 02/01/2010 01:39:09 S08
RepID09 02/01/2010 01:39:09 S09
RepID23 02/01/2010 01:39:18 S09
RepID19 02/01/2010 01:40:09 S09
RepID21 02/01/2010 01:40:18 S09
RepID28 02/01/2010 01:40:27 S09
RepID43 02/01/2010 01:40:09 S14

등등 총 48시간의 시간이 소요됩니다. 분당 60개가 넘는 이벤트가 발견된 경우에만 행을 인쇄하고 싶습니다.

예를 들어, 다음 명령을 사용하면 1분 동안 발생한 이벤트 수를 계산할 수 있습니다.

grep "02/01/2010 01:39" events.dat | wc -l

예를 들어 60이 반환되며 이는 분당 최대 이벤트 수입니다.

동일한 작업을 수행하면서 전체 48시간 동안 매분 확인하고 분당 60개 이상의 이벤트가 발견된 행만 인쇄하려면 어떻게 해야 합니까? 미리 감사드립니다

답변1

이상적으로는 파일을 한 번만 처리하고 메모리에 가능한 한 적게 저장하는 것이 좋습니다. 에서는 awk다음을 수행할 수 있습니다.

awk -v n=60 '
  {
    t = $2 substr($3, 1, 5);
    if (t == last_t) {
      if (++lines > n)
        print
      else
        if (lines == n)
          print saved $0
        else
          saved = saved $0 RS
    } else {
      saved = $0 RS
      lines = 1
      last_t = t
    }
  }' < your-file

이 접근 방식의 몇 가지 장점은 다음과 같습니다.

  • 이는 스트림 처리 지향적입니다. 입력은 도착하자마자 처리되고, 출력은 가능한 한 빨리 방출됩니다(라인 60이 보이면). 이를 통해 실시간 출력을 사후 처리할 수 있습니다( 에서와 마찬가지로 tail -fn +1 log_file).
  • 명령( )을 한 번만 실행하므로 awk최대한 효율적입니다. 반대 극단은루프에서 여러 명령 실행. 쉘 스크립트에서 가장 비용이 많이 드는 작업은 일반적으로 명령을 분기하고 실행하는 것입니다. 최적화란 이러한 상황을 최대한 최소화하는 것을 의미합니다.
  • 최대 60개의 행만 메모리에 저장하므로 메모리 사용량이 제한됩니다(행 자체의 크기가 제한되어 있다고 가정).
  • awk코드는 매우 명확하고 설명이 필요합니다. 이제 크기가 중요하다면 크기를 줄여 다음과 같이 한 줄에 넣을 수도 있습니다.

    awk '{t=$2substr($3,1,5);if(t==l){if(++i>n)print;else if(i==n)print s$0;else s=s$0RS}else{s=$0RS;i=1;l=t}}' n=60 file
    

답변2

이것이 가장 효율적인 솔루션은 아니지만 먼저 분당 이벤트 수를 계산한 다음, 수가 60보다 크면 각 분에 대해 파일을 grep할 수 있습니다.

sort -k 2,3 your_log_file \
| uniq -c -s 8 -w 16 \
| while read count _ date time _; do
    [ "$count" -ge 60 ] && grep -F " $date ${time%:*}" your_log_file
done

노트:

  • 위의 기본 예에서는 먼저 파일을 시간순으로 정렬합니다.
  • 이것이 관심 있는 유일한 정보인 경우 처음 두 줄은 분당 이벤트 수를 제공합니다.

파일이 이벤트로 가득 차면 grep해당 파일에 대해 많은 작업을 수행하게 될 가능성이 높습니다. 더 나은 해결책은 로그 파일을 순차적으로 읽고 마지막 줄을 기억하는 것입니다. 다음 분에 도달했을 때 이 줄의 수가 60보다 크면 해당 줄을 인쇄하십시오. 그러한 솔루션에 대해서는 Stéphane의 답변을 참조하십시오.

답변3

이러한 방식으로 사용 가능한 시간(분)을 분리할 수 있습니다.

root@debian:# awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq
01/01/2010 20:56
02/01/2010 01:39
02/01/2010 01:40
02/01/2010 20:56

그런 다음 이 값을 사용하여 배열을 할당할 수 있습니다.

수정된 코드:

readarray -t stamps < <(awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq)
for stamp in "${stamps[@]}";do
ev=$(grep "$stamp" b.txt |wc -l)
echo "In $stamp found $ev events "
#if [ "$ev" -gt 60 ]; then
# do the stuff
#fi
done

산출:

In 01/01/2010 20:56 found 7 events 
In 02/01/2010 01:39 found 11 events 
In 02/01/2010 01:40 found 4 events 
In 02/01/2010 20:56 found 7 events 

답변4

awk '{ print $2 " " $3 }' < input \
| cut -c1-16                      \
| sort                            \
| uniq -c                         \
| awk '{ if ($1 > 60) print $2 }'

즉, 날짜 및 시간 필드를 가져오고, 초를 제거하고, 결과를 정렬하고(참고: 날짜가 ISO 형식인 경우 더 잘 작동합니다), 각 고유 날짜/시간 조합에 대한 개수를 찾은 다음 Count > 60을 사용하여 인쇄합니다.

관련 정보