我有一个带有管道的脚本,其中数据由程序限制。每 20 分钟发送一次吞吐量状态标准错误,我只是将其重定向到一个文件:
command | cstream -t -512k -T 1200 -B 64m 2>>/home/user/totals.log | command
我还可以发送 SIGUSR1 信号到流媒体( kill -s 10 PID
) 并且它会产生与我像我一样设置间隔时完全相同的输出,并向文件中添加一行。这个想法是您可以设置间隔并按需查询状态。输出的格式如下所示,整个文件中只有一个空白字符,并以换行符结尾:
...
1931255808 B 1.8 GB 3683.6 s (1:01 h) 524289 B/s 512.00 KB/s
2560401408 B 2.4 GB 4883.6 s (1:21 h) 524289 B/s 512.00 KB/s
3189547008 B 3.0 GB 6083.6 s (1:41 h) 524289 B/s 512.00 KB/s
3818692608 B 3.6 GB 7283.6 s (2:01 h) 524289 B/s 512.00 KB/s
4447838208 B 4.1 GB 8483.6 s (2:21 h) 524289 B/s 512.00 KB/s
10829824 B 10.3 MB 20.65 s 524487 B/s 512.19 KB/s
您可以看到数据进度,但不能只对每列求和(或平均)。此示例中只有 2 个事件(第 1-5 行、第 6 行),即我使用了该脚本两次。恰巧我们可以添加最后两行 - 因为我重新启动了它并且我们有那一刻的快照,但这是任意的。这导致当我退出命令并重新启动它时会发生什么,正如您在最后一行看到的那样 - 计数器当然被重置。
目标是获得我随时间启动的脚本的所有实例的状态输出的累积总数。我通常不会一次启动多个实例。所以我正在考虑添加到我的脚本中(“sane”仅适用于脚本的一个实例):
- 首先删除日志中除最后一行以外的所有内容
- 最后,当脚本退出时,使其将其状态写入日志
- 第一行和最后一行的每一列的总和/平均值
- 删除所有中间线
恐怕我无法将这些点联系起来。设计和实现我想要的东西的最简单和最好的方法是什么?复杂性是否压倒了好处?我是否应该只专注于在日志数据填满时使用简单的命令来操作日志数据?
答案1
好吧,根据你所展示的内容,我确实设法相当可靠地分割它,但是这个数据有一个严重的问题:它是不正常。你有人类友好的这里的价值观 - 这不好。例如第一行和最后一行之间的MB
差异GB
- 处理是很多您不必做的额外工作 - 为什么不只是字节计数?这是怎么回事([h]:[mm])
——为什么它在第一行而不是最后一行,为什么不是 Unix 时间?
老实说,这根本不是您应该记录的数据 - 它不是很有用。当然,它对你来说更容易阅读,但你会读 10,000 行吗?我认为你不愿意,这就是你问这个问题的原因。您需要更改该输出 - 根本不获取任何字母,仅获取自纪元以来的字节数和秒数。这样做,这将是一个很多对你来说更容易。
现在,这就是我所说的做过做:
set -- $(
sed '$bl;1H;d;:l;x;G
s/([1-9][^)]*) //;h
s/\n/First:& /
s/[^:]\(\n\)/&Last:\1 /
w /dev/fd/2
g' <<\DATA
1931255808 B 1.8 GB 3683.6 s (1:01 h) 524289 B/s 512.00 KB/s
2560401408 B 2.4 GB 4883.6 s (1:21 h) 524289 B/s 512.00 KB/s
3189547008 B 3.0 GB 6083.6 s (1:41 h) 524289 B/s 512.00 KB/s
3818692608 B 3.6 GB 7283.6 s (2:01 h) 524289 B/s 512.00 KB/s
4447838208 B 4.1 GB 8483.6 s (2:21 h) 524289 B/s 512.00 KB/s
10829824 B 10.3 MB 20.65 s 524487 B/s 512.19 KB/s
DATA
)
第一sed
行就是获取第一行和最后一行并将它们放入相同的模式空间中进行sed
编辑所需的全部,每行前面都有一个\n
ewline 字符。该声明执行了所有这些操作:
$bl;1H;d;:l;x;G
下一行清除了数据的时髦超时(这是问题的一部分),然后将结果的额外副本存储在h
旧空间中:
s/([1-9][^)]*) //;h
接下来三行插入单词第一的:和最后的:然后在各自的行之前\n
添加 ewline 和<tab>
个字符,并将结果写入stderr
:
s/\n/First:& /
s/[^:]\(\n\)/&Last:\1 /
w /dev/fd/2
最后sed
一行只是g
将第二个副本从h
旧空间中取出,并用它覆盖当前模式空间,然后sed
执行默认操作,打印最终模式空间,然后再\n
打印一行。诚然,目前的结果并不那么令人印象深刻。运行上面的脚本只会输出以下内容:
First:
1931255808 B 1.8 GB 3683.6 s 524289 B/s 512.00 KB/s
Last:
10829824 B 10.3 MB 20.65 s 524487 B/s 512.19 KB/s
但我故意把set
结果放到shell数组中和sed
出于某种原因,在 的模式空间中保持这两行可访问。例如,按照最后g
一行sed
- 如果您愿意 - 您可以使用如下所示的模式空间:
\n1931255808 B 1.8 GB 3683.6 s 524289 B/s 512.00 KB/s\n10829824 B 10.3 MB 20.65 s 524487 B/s 512.19 KB/s$
或者,如果您按原样保留它,只将以下内容附加到已有的内容中......
printf '%s LINE, FIELDs 1 and 2: %s and %s' \
FIRST "$1" "$2" LAST "${11}" "${12}"
你的输出看起来应该像这样:
FIRST LINE, FIELDs 1 and 2: 1931255808 and B
LAST LINE, FIELDs 1 and 2: 10829824 and B
这是除了stderr
它已经提供的输出之外的。