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

私はこの問題を解決しようとしましたが、運がありませんでした。'.'ストリームの3番目と5番目の列で最後に発生したポート番号を変更してからすぐに16進数に変更するにはどうすればよいですか?

答え1

そしてperl

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

\sスペース()の後に続く単語で構成される単語を見つけます。1つ以上の順序( +)空白ではない\S)、ドット、および1つ以上の数値シーケンス()を使用し、最後の部分(開始部分がと表示されます)を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()の3番目の引数を一致させるには、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進数で印刷します。

関連情報