我有以下 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
端口号以十进制表示。如何将其通过管道传输到 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
如果我有端口号,我用它将其转换为十六进制:
echo 33101 | sed -e 's/.*://' | xargs printf "%x\n"
814d
我一直在尝试解决这个问题,但没有运气。如何替换'.'
流的第三列和第五列中最后一次出现后的端口号,然后即时将其更改为十六进制?
答案1
和perl
:
perl -pe 's/\s\S+\.\K\d+/sprintf "%x", $&/ge' < your-file
它查找由空格 ( \s
) 和后跟组成的单词一个或多个的序列( +
)非空白( \S
)、一个点和一个或多个数字的序列 ( ) 并用十进制格式的相同 ( )\d+
替换结束部分(其开头标记为) (总体上,替换被评估为 Perl 代码)。\K
$&
x
g
e
答案2
在每个 UNIX 机器上的任何 shell 中使用任何 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
使用 GNU awk 将第三个参数匹配到 match():
$ 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
谢谢大家的回答!他们都工作!不过,我也想在这里发布我的解决方案。现在我知道我特别要求这样sed
做,awk
但我的输入是一个tcpdump
流,我想将端口号修改为十六进制。所以我浏览了源代码并更改了以下几行:
(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 以十六进制打印端口。