sed/awk: "."가 마지막으로 나타난 다음 줄의 숫자를 바꿉니다.

sed/awk: "."가 마지막으로 나타난 다음 줄의 숫자를 바꿉니다.

다음 tcpdump 스트림이 있습니다.

Current:
07:36:03.848461 IP 172.17.3.41.33101 > 172.17.3.43.17408: UDP, length 44
07:36:03.848463 IP 172.17.3.42.33101 > 172.17.3.43.17409: UDP, length 44
07:36:03.848467 IP SYSTEM-A.33101 > 172.17.3.43.17418: UDP, length 45
07:36:03.848467 IP SYSTEM-B.33101 > 172.17.3.43.17419: UDP, length 45

포트 번호는 10진수 표기법으로 표시됩니다. 포트 번호가 16진수로 변경된 동일한 스트림으로 만들기 위해 스트림을 sed 또는 awk로 파이프하여 수정하려면 어떻게 해야 합니까?

Expected:
07:36:03.848461 IP 172.17.3.41.814d > 172.17.3.43.4400: UDP, length 44
07:36:03.848463 IP 172.17.3.42.814d > 172.17.3.43.4401: UDP, length 44
07:36:03.848467 IP SYSTEM-A.814d > 172.17.3.43.440a: UDP, length 45
07:36:03.848467 IP SYSTEM-B.814d > 172.17.3.43.440b: UDP, length 45

포트 번호가 있는 경우 이를 사용하여 16진수로 변환합니다.

echo 33101 | sed  -e 's/.*://' | xargs printf "%x\n"
814d

나는 이 문제를 해결하려고 노력했지만 운이 없었습니다. '.'스트림의 세 번째 및 다섯 번째 열에서 마지막으로 발생한 포트 번호를 바꾼 다음 즉시 16진수로 변경하려면 어떻게 해야 합니까 ?

답변1

그리고 perl:

perl -pe 's/\s\S+\.\K\d+/sprintf "%x", $&/ge' < your-file

\s공백( ) 뒤에 오는 단어로 구성된 단어를 찾습니다.하나 이상의 순서( +)공백이 아닌( \S), 점 및 하나 이상의 숫자 시퀀스 ( )를 사용하고 끝 부분(시작 부분이 로 표시됨)을 10진수 형식의 동일한 ( )로 바꿉니다 \d+(일반적으로 대체는 Perl 코드로 평가됩니다).\K$&xge

답변2

모든 UNIX 시스템의 모든 쉘에서 awk를 사용하십시오.

$ cat tst.awk
function mkPortHex(fldNr,       port, sfx) {
    port = sfx = $fldNr
    sub(/.*\./,"",port)
    sub(/.*[0-9]/,"",sfx)
    sub(/[^.]+$/,sprintf("%x%s",port,sfx),$fldNr)
}
{
    mkPortHex(3)
    mkPortHex(5)
    print
}

$ awk -f tst.awk file
07:36:03.848461 IP 172.17.3.41.814d > 172.17.3.43.4400: UDP, length 44
07:36:03.848463 IP 172.17.3.42.814d > 172.17.3.43.4401: UDP, length 44
07:36:03.848467 IP SYSTEM-A.814d > 172.17.3.43.440a: UDP, length 45
07:36:03.848467 IP SYSTEM-B.814d > 172.17.3.43.440b: UDP, length 45

match()에 대한 세 번째 인수를 일치시키려면 GNU awk를 사용하십시오.

$ cat tst.awk
function mkPortHex(fldNr) {
    match($fldNr,/(.*\.)([0-9]+)(:?)/,a)
    $fldNr = a[1] sprintf("%x",a[2]) a[3]
}
{
    mkPortHex(3)
    mkPortHex(5)
    print
}

$ awk -f tst.awk file
07:36:03.848461 IP 172.17.3.41.814d > 172.17.3.43.4400: UDP, length 44
07:36:03.848463 IP 172.17.3.42.814d > 172.17.3.43.4401: UDP, length 44
07:36:03.848467 IP SYSTEM-A.814d > 172.17.3.43.440a: UDP, length 45
07:36:03.848467 IP SYSTEM-B.814d > 172.17.3.43.440b: UDP, length 45

답변3

질문 필드 3과 5에 표시된 것처럼 필드 번호가 일정한 경우 - 시도해 보세요.

awk '
function CHX(FLD)   {n = split ($FLD, T, ".")
                     sub (T[n] "$", sprintf ("%X", T[n]), $FLD)
                    }
    {CHX(3)
     CHX(5)
    }
1
' file
07:36:03.848461 IP 172.17.3.41.814D > 172.17.3.43.4400 UDP, length 44
07:36:03.848463 IP 172.17.3.42.814D > 172.17.3.43.4401 UDP, length 44
07:36:03.848467 IP SYSTEM-A.814D > 172.17.3.43.440A UDP, length 45
07:36:03.848467 IP SYSTEM-B.814D > 172.17.3.43.440B UDP, length 45

예를 들어 필드 5의 후행 콜론은 다음과 같습니다.

awk '
function CHX(FLD)       {n = split ($FLD, T, "[^0-9]")
                         TRM = ""
                         if (!T[n])     {n--
                                         TRM = substr ($FLD, length($FLD))
                                        }
                         sub (T[n] TRM "$", sprintf ("%X%s", T[n], TRM), $FLD)
                        }
        {CHX(3)
         CHX(5)
        }
1
' file

답변4

답변해 주셔서 감사합니다. 그들은 모두 작동합니다! 그러나 여기에도 내 솔루션을 게시하고 싶습니다. 이제 나는 이것을 구체적으로 요구한다는 것을 알고 있지만 sedawk입력은 tcpdump스트림이고 포트 번호를 16진수로 수정하고 싶습니다. 그래서 소스 코드를 살펴보고 다음 줄을 변경했습니다.

(void)snprintf(buf, sizeof(buf), "%u", i);

도착하다

(void)snprintf(buf, sizeof(buf), "%x", i); // prints hexadecimal

(void)snprintf(buf, sizeof(buf), "%u", i);

도착하다

(void)snprintf(buf, sizeof(buf), "%x", i); // prints hexadecimal

바이너리를 컴파일하고 이제 tcpdump는 포트를 16진수로 인쇄합니다.

관련 정보