我的文件(来自网络传感器的 TCP 转储)具有以下形状:
20:06:57.049686 IP(tos 0x0、ttl 64、id 26871、偏移量 0、标志 [DF]、原始 UDP (17)、长度 68) e108-193.eduroam.tugraz.ac.at.34225 > e158-093.eduroam.tugraz.ac.at.personal-agent: [udp sum ok] UDP,长度 40 0x0000: 4500 0044 68f7 4000 4011 25c7 8083 d0bf E..Dh.@.@.%..... 0x0010:8083 da24 85b1 15b3 0030 1e8b 3132 3033 ...$.....0..1203 0x0020: 3132 2e37 3836 3036 2c20 332c 2020 2030 12.78606,.3,...0 0x0030: 2e31 3533 2c20 2d30 2e31 3533 2c20 2039 .153,.-0.153,..9 0x0040: 2e39 3630 .960 20:06:57.113591 IP(tos 0x0、ttl 64、id 26872、偏移量 0、标志 [DF]、原始 UDP (17)、长度 68) e108-193.eduroam.tugraz.ac.at.34225 > e158-093.eduroam.tugraz.ac.at.personal-agent: [udp sum ok] UDP,长度 40 0x0000: 4500 0044 68f8 4000 4011 25c6 8083 d0bf E..Dh.@.@.%..... 0x0010:8083 da24 85b1 15b3 0030 148f 3132 3033 ...$.....0..1203 0x0020: 3132 2e38 3336 3131 2c20 332c 2020 2d30 12.83611,.3,..-0 0x0030: 2e31 3533 2c20 2d30 2e34 3630 2c20 2039 .153,.-0.460,..9 0x0040: 2e39 3630 .960 20:06:57.188105 IP(tos 0x0、ttl 64、id 26873、偏移量 0、标志 [DF]、原始 UDP (17)、长度 68) e108-193.eduroam.tugraz.ac.at.34225 > e158-093.eduroam.tugraz.ac.at.personal-agent: [udp sum ok] UDP,长度 40 0x0000: 4500 0044 68f9 4000 4011 25c5 8083 d0bf E..Dh.@.@.%..... 0x0010:8083 da24 85b1 15b3 0030 1b80 3132 3033 ...$.....0..1203 0x0020: 3132 2e38 3836 3135 2c20 332c 2020 2d30 12.88615,.3,..-0 0x0030: 2e31 3533 2c20 2d30 2e33 3036 2c20 2039 .153,.-0.306,..9 0x0040: 2e38 3037 .807 20:06:57.200719 IP(tos 0x0、ttl 64、id 26874、偏移量 0、标志 [DF]、原始 UDP (17)、长度 68) e108-193.eduroam.tugraz.ac.at.34225 > e158-093.eduroam.tugraz.ac.at.personal-agent: [udp sum ok] UDP,长度 40 0x0000: 4500 0044 68fa 4000 4011 25c4 8083 d0bf E..Dh.@.@.%..... 0x0010:8083 da24 85b1 15b3 0030 2884 3132 3033 ...$.....0(.1203 0x0020: 3132 2e39 3336 3135 2c20 332c 2020 2030 12.93615,.3,...0 0x0030: 2e31 3533 2c20 2d30 2e31 3533 2c20 2039 .153,.-0.153,..9 0x0040: 2e38 3037 .807
我需要将其转换为这个或类似的形状:
20:06:57.049686 26871, 120312.78606,.0.153,.-0.153,..9.960 20:06:57.113591 26872, 120312.83611,-0.153,.-0.460,..9.960 20:06:57.188105 26873, 120312.88615,-0.153,.-0.306,..9.807 20:06:57.200719 26874, 120312.93615,.0.000,.-0.153,..9.807
到目前为止,vb 脚本做得很好,但现在我们需要实时显示这些数据,因此必须有一个脚本在更新日志时使用 grep/cut/awk 任何命令来执行此操作,因此,在文件完成后打开文件并在 libre-office 中使用 vbscript 已经不再好了。
有什么建议么?
答案1
我重新考虑了我的方法,并决定使用H
旧空间既容易又更强大。正如您提到的文件在制表符上分隔而不是空格,简单的解决方法是使用字符类而不是文字空格字符。不过,关于类的问题是它们往往会变得有点庞大,所以我通常更喜欢在使用它们时将它们包装在替换中。我还将通过将其包装在 shell 函数中将其打包为一个简单的命令。
又来了,又不同了:
#!/bin/sh
robot() (s=[:blank:];LC_ALL=C \
sed "s/^[$s].*[$s]//;s/\.\.*/./g
/[$s][^i$]*[^1-9d]*[d$s]*/!{H;\$!d
}; s//,/;x;s///;s/\n//g
s/,\.\([-1-9]*\)0*//
s//,\1/g;s//,+.\1/g" "$@"
)
robot "$@"
sed
如果从上面删除顶部和底部行,则可以将其复制/粘贴到正在运行的 POSIX 兼容 shell,其中包含 POSIX 兼容的$PATH
.否则,上面的内容可以逐字写入$PATH
.无论哪种方式,我都可以将其称为INPUT| robot
orrobot <infile
或robot infile1 infile[2-9] -
。喜欢:
robot <<\DATA
20:06:57.049686 IP (tos 0x0, ttl 64, id 26871, offset 0, flags [DF], proto UDP (17), length 68)
e108-193.eduroam.tugraz.ac.at.34225 > e158-093.eduroam.tugraz.ac.at.personal-agent: [udp sum ok] UDP, length 40
0x0000: 4500 0044 68f7 4000 4011 25c7 8083 d0bf E..Dh.@.@.%.....
0x0010: 8083 da24 85b1 15b3 0030 1e8b 3132 3033 ...$.....0..1203
0x0020: 3132 2e37 3836 3036 2c20 332c 2020 2030 12.78606,.3,...0
0x0030: 2e31 3533 2c20 2d30 2e31 3533 2c20 2039 .153,.-0.153,..9
0x0040: 2e39 3630 .960
DATA
而旧版本打印...
20:06:57.049686,26871,.0.120312.78606,.3,.0.153,-0.153,.9.960
这个打印...
20:06:57.049686,26871,120312.78606,+.153,-.153,9.960
现在它剥离了领先的.点或者0零从各个字段中删除.3
之前获得的虚假字段,该字段未包含在输出中。它还+
为可能以 开头的字段的输出添加了符号-短跑。
也许它做得太多了——老实说,我不知道所有这些领域应该如何结合在一起,这只是我最好的猜测。我尝试将其分解如下,但如果您出于任何原因希望看到它做一些不同的事情,请随时询问。
字符类[:blank:]
匹配区域设置定义的任何水平空白字符 - 因此它可以是空格或制表符,并且没有区别。考虑到语言环境,我决定C
在这里显式指定语言环境,因为在进行文本处理时它始终是最明智的事情 - 在C
语言环境中,保证每个输入字节匹配单个字符sed
(当它做类似的事情时,这可能意味着很多.*
)。不过,函数中定义的任何状态仅是函数的本地状态,除了打印到 之外,不会影响执行环境stdout
。
流动:
在脚本的第一行中,sed
将删除从第一个到最后一个出现的字符序列[[:blank:]]
如果该行以 1 开头。然后,它还会.dot
用单个 s替换任何一系列s .dot
。
下一行有点毛茸茸的。它是一个单一地址,用于处理多阶段s///
替换,使用空地址来引用脚本中的最后一个非空地址。
/[$s][^i$]*[^d1-9]*[d$s]*/
唯一的定地址中的匹配项至少有一个空白 - 匹配项中的所有其他序列零次*
或多次出现- 所以它不能匹配根本不包含空格的行。这意味着它只匹配块标题,因为我们刚刚删除了以 1 开头的任何行中的所有空格。
因此,我做的第一件事是将其与非标题行进行比较,如果它们不匹配,则将它们放置在H
旧空间中,并从输出中删除所有不是最后的行。因此,这里的最后一行会与脚本其余部分的所有块标题集中在一起,因为从这里开始,这些是唯一将应用任何规则的行。!
$!d
!
$
$
sed
将该地址与标题行进行比较:
20:06:57.049686 IP (tos 0x0, ttl 64, id 26871, offset 0, flags [DF], proto UDP (17), length 68)
[$s]
- 匹配第一个空白 - 之前IP
。[^i$]*
- 匹配64,[[:blank:]]
.[^d1-9]* - matches the
我`。[d$s]*
- 匹配d
和[[:blank:]]
所以当我这样做时,s//,/
所有这些都被替换为逗号。这不会影响我们刚刚让它通过的最后一行,因为它无法与前导[[:blank:]]
.即使确实如此,任何更改都无关紧要,因为对于最后一行,唯一打印的副本是在H
旧空间中等待我们的副本,我们仅在更改后对其进行操作x
。这是下一个命令 - 并且普遍适用 - 所以我们现在正在使用一个看起来像这样的模式空间......
20:06:57.049686,26871, offset 0, flags [DF], proto UDP (17), length 6\
8)\n40\nE.Dh.@.@.%.\n.$.0.1203\n12.78606,.3,.0\n.153,.-0.153,.9\n.960$
...这代表了已经应用于前一个块标题以及H
此后所有行的编辑 - 正如您可以看到的那样,\n
那里用 ewline 转义符分隔。
让我们再次将其与我们的长地址进行比较:
[$s]
[[:blank:]]
- 匹配紧接在 之前出现的第一个offset
。[^i$]*
- 一直匹配但不包括第一个出现的$
字符。[^d1-9]*
- 火柴.0.
。[d$s]*
- 根本不匹配。
所以,像以前一样,s///
把所有这些都抹掉。删除所有\n
ewlines之后s/\n//g
,现在模式空间看起来像:
20:06:57.049686,26871,120312.78606,.3,.0.153,.-0.153,.9.960
...这几乎就是旧版本留下的地方。但我对递归匹配很感兴趣,所以我添加了一些。你不应该这样做,虽然我可能可以做得更好,因为我发现了其中的漏洞,但最后一点可能是在第二个过滤器中使用针对 csv 的新脚本更好地完成的事情。尽管如此,它肯定适用于示例输入,并且可能适用于更多输入,但我想我可能会否认它,以防它不适用,或者如果它适用但不符合您的期望。最后两行可以轻松删除,以获得与您检查此答案时接受的输出一致的输出 - 如上所示。
s/,\.\([-1-9]*\)0*//
这会删除第一个出现的序列,逗号随后是一个。点,然后零个或多个-短跑或不为零的数字以及任何尾随零。这将从,.3
输出中删除该字段。
使用全局标志第二次应用g
并保存\1
不被删除,s//,\1/
如下所示:
20:06:57.049686,26871,120312.78606,.0.153,.-0.153,.9.960
...进入...
20:06:57.049686,26871,120312.78606,.153,-.153,9.960
再一次进行g
全局应用并添加一个+.
类似的内容s//,+./g
,它进一步修改模式空间以读取:
20:06:57.049686,26871,120312.78606,+.153,-.153,9.960
...这就是在下一个行周期开始stdout
之前自动打印的内容。sed
如果任何读者实际上已经做到了这一点并且对我所说的旧版本的含义感到好奇,您会在编辑历史记录中找到它以及它如何工作的详细解释
输入此脚本,您的整个示例输入将得到:
20:06:57.049686,26871,120312.78606,+.153,-.153,9.960
20:06:57.113591,26872,120312.83611,-.153,-.460,9.960
20:06:57.188105,26873,120312.88615,-.153,-.306,9.807
20:06:57.200719,26874,120312.93615,+.153,-.153,9.807