2013-05-24 4 views
1

연습 문제로 awk에서 문제를 해결하려고하는데 문제가 있습니다. awk (또는 gawk)가 모든 고유 한 소스 IP 주소의 고유 한 대상 포트를 인쇄 할 수있게하려고합니다.

원본 IP 주소는 필드 1 ($ 1)이고 대상 포트는 필드 4 ($ 4)입니다.awk : 동 Log (conn.log)에서 각 소스 IP에 대해 표시되는 대상 포트 목록을 만듭니다.

Cut for brevity: 
SourceIP   SrcPort DstIP   DstPort 
192.168.1.195  59508 98.129.121.199 80 
192.168.1.87  64802 192.168.1.2  53 
10.1.1.1   41170 199.253.249.63 53 
10.1.1.1   62281 204.14.233.9 443 

각 소스 IP를 인덱스에 배열로 저장한다고 생각합니다. 그러나 목적지 포트를 값으로 저장하는 방법에 대해서는 잘 모르겠습니다. 어쩌면 인덱스의 값인 문자열에 계속 추가 할 수 있습니다. "80", ... "80,443"... 각 경기마다. 그러나 아마도 이것이 최선의 해결책은 아닙니다.

나는 출력에 너무 신경 쓰지 않고, awk에서 어떻게 접근 할 수 있는지보고 싶다. 비록, 출력을 위해 나는

awk '{ if (NR == 1) next; arr[$1,$4] = $4 } END { for (i in arr) print arr[i] }' infile 

,

Source IP:dstport, dstport, dstport 
192.168.1.195:80,443,8088,5900 

나는이 같은 땜질하고있어, 같은 것을 생각하지만, 2 차원의 요소와 그 값을 출력하는 방법을 알아낼 수 없습니다 차원 배열. 각 포트가 요소의 값을 덮어 쓰고 있기 때문에이 행을 따라 무언가가 고유 한 대상 포트 작업을 처리하는 것 같습니다.

참고 :awk/gawk 해결 방법이 있습니다.

해결책 EDIT : 내 질문에서 언급 한 고유 대상 포트를 인쇄하고 열 머리글 행을 건너 뛰기 위해 Kent 솔루션을 약간 수정했습니다.

awk '{ if (NR == 1) next ; if (a[$1] && a[$1] !~ $4) a[$1] = a[$1]","$4; else a[$1] = $4 } END {for(x in a)print x":"a[x]}' 

답변

2

하나 개의 방식에있다 awk :

awk '{k=$1;a[k]=a[k]?a[k]","$4:$4}END{for(x in a)print x":"a[x]}' file 
사용자의 예에 53,691,363,210

는 출력은 :

kent$ awk '{k=$1;a[k]=a[k]?a[k]","$4:$4}END{for(x in a)print x":"a[x]}' file                        
192.168.1.195:80 
192.168.1.87:53 
10.1.1.1:53,443 

k=$1;a[k]=a[k]?a[k]","$4:$4 

정확히 동일

EDIT (I 제목 라인 생략) 등 :

if (a[$1])     # if a[$1] is not empty 
    a[$1] = a[$1]","$4  # concatenate $4 to it separated by "," 
else       # else if a[$1] is empty 
    a[$1] = $4    # let a[$1]=$4 

절약하기 위해 k=$1을 사용했습니다. 어떤 타이핑. 또한 x=boolean?a:b 표현

나는 코드가 당신을 이해할 수 있기를 바랍니다.

+0

켄트, 예제의 첫 부분, 즉 END 이전의 모든 것을 신중하게 설명 할 수 있습니까? 감사. – jonschipp

+0

+1. 나는 두 번 지나서 생각하고 있었다. 그러나 이것은 너무 달콤하다! –

+0

@jonschipp 설명에 대한 편집을 참조하십시오 – Kent

1

좀 더에게 배열의 해시 같은 데이터 구조를 만드는 posibilities을 좋아하기 때문에 내가 perl를 사용하여 솔루션을 선호는 :

perl -ane ' 
    ## Same BEGIN block than AWK. It prints header before processing any input. 
    BEGIN { printf qq|%s:%s\n|, q|Source IP|, q|dstport| } 

    ## Skip first input line (header). 
    next if $. == 1; 

    ## This is what you were thinking to achieve. Store source IP as key of a 
    ## hash, and instead of save a string, it will save an array with all 
    ## ports. 
    push @{ $ip{ $F[0] } }, $F[ 3 ]; 

    ## Same END block than AWK. For each IP, get all ports saved in the array 
    ## and join them using a comma. 
    END { printf qq|%s:%s\n|, $_, join q|,|, @{ $ip{ $_ } } for keys %ip } 

' infile 

이 산출 :

여기
Source IP:dstport 
192.168.1.195:80 
10.1.1.1:53,443 
192.168.1.87:53 
+0

비레이 설명이나 댓글을 주시겠습니까? 나는 펄을 사용한 적이 없다. – jonschipp

+0

@jonschipp : 스크립트의 각 줄에 주석을 추가하는 대답을 편집했습니다. 나는 그것이 지금 이해하기 더 쉬기를 바랍니다. – Birei

+0

차가운 용액. Thx – jonschipp