计算 bash/perl 中的时间戳(带关键字)
Calculate timestamps in bash/perl (with keywords)
在我公司,有不同的客户位置"city-01-r-01"和"city-02-r-01"等等。因此,如果无法到达该位置,监控软件会生成状态为 "UNKNOWN" 或 "CRITICAL" 的时间戳。当该位置再次可达时,状态显示为 "OK"。我需要计算无法访问该位置的持续时间。
监控软件为所有客户位置生成此单个文件(.txt 格式),格式如下:
- 2015-08-02 07:18:30;city-01-r-01;未知
- 2015-08-02 07:33:25;city-01-r-01;OK
- 2015-08-03 12:56:50;city-02-r-01;严重
- 2015-08-03 13:02:49;city-02-r-01;OK
我需要从 .txt 文件中提取上述信息并计算每个位置的不可达性。
我的输出应该是另一个 .txt 文件,格式如下:
(脚本可以是 bash 或 perl 或任何其他脚本语言)
- city-01-r-01 在 ___(分钟)____(秒)内无法访问 ____(日期)
- city-02-r-01 在 ___(分钟)____(秒)内无法访问 ____(日期)
我今天在谷歌上搜索了一下,发现我需要使用 IFS(用于逐行阅读)和 while/do 循环来实现这一点。但是,我不确定如何实现结果。
有很多方法可以用 perl、python、SQLite、C、C++、java、tcl、bash...这里是 GNU awk,用于文本文件处理的 GNU 瑞士刀:
$ cat csv2ts.awk
BEGIN { FS = ";" }
{
t = ;
gsub(/[-:]/, " ", t);
t = mktime(t);
}
== "UNKNOWN" || == "CRITICAL" { c[] = t }
== "OK" {
d = t - c[];
printf("%s was unreachable for %d (minutes) %d (seconds) on %s (date)\n",
, d / 60, d % 60, strftime("%F", t));
}
$ awk -f csv2ts.awk data.csv > data.txt
$ cat data.txt
city-01-r-01 was unreachable for 14 (minutes) 55 (seconds) on 2015-08-02 (date)
city-02-r-01 was unreachable for 5 (minutes) 59 (seconds) on 2015-08-03 (date)
awk 脚本存储在文件 csv2ts.awk
中,您的原始数据在 data.csv
中,输出结果在 data.txt
中。 awk 脚本使用';'作为字段分隔符 (FS = ";"
)。它使用第一个字段 (gsub
、mktime
) 计算每条记录的时间戳(以秒为单位)。它构建了一个由客户位置(字段#2)索引的时间戳数组(c
)。事件日期是使用 strftime
根据第二个事件 (OK
) 的时间戳计算得出的。剩下的应该很容易理解了。
请注意您的问题未明确说明:
- C市的记录在文件中是连续的吗?
- 您希望日期的确切输出格式是什么?
- 当不可访问时间跨过天数边界时会发生什么?
- 如果对于给定的位置,事件的顺序不是“未知、正常”或“严重”、“正常”,而是其他任何情况,例如“正常”、“正常”或“未知、严重”?
- 如果对于给定位置,第一个事件正常怎么办?
- 如果对于给定位置,最后一个事件不正常怎么办?
如果您完成规范,调整 awk 脚本应该相当容易。
使用 Perl 非常简单 Time::Piece and Time::Seconds。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my %outages;
my $time_format = '%Y-%m-%d %H:%M:%S';
while (<DATA>) {
chomp;
my ($timestamp, $city, $status) = split /;/;
my $time = Time::Piece->strptime($timestamp, $time_format);
if ($status ne 'OK') {
$outages{$city} = $time;
} else { # status is now ok
my $duration = $time - $outages{$city};
say "city $city was unreachable for ",
$duration->pretty, ' on ', $outages{$city}->date;
}
}
__END__
2015-08-02 07:18:30;city-01-r-01;UNKNOWN
2015-08-02 07:33:25;city-01-r-01;OK
2015-08-03 12:56:50;city-02-r-01;CRITICAL
2015-08-03 13:02:49;city-02-r-01;OK
(为简单起见,我将数据放在 DATA
文件句柄中。修复它以从外部文件读取数据留作 reader 的练习。)
在我公司,有不同的客户位置"city-01-r-01"和"city-02-r-01"等等。因此,如果无法到达该位置,监控软件会生成状态为 "UNKNOWN" 或 "CRITICAL" 的时间戳。当该位置再次可达时,状态显示为 "OK"。我需要计算无法访问该位置的持续时间。
监控软件为所有客户位置生成此单个文件(.txt 格式),格式如下:
- 2015-08-02 07:18:30;city-01-r-01;未知
- 2015-08-02 07:33:25;city-01-r-01;OK
- 2015-08-03 12:56:50;city-02-r-01;严重
- 2015-08-03 13:02:49;city-02-r-01;OK
我需要从 .txt 文件中提取上述信息并计算每个位置的不可达性。
我的输出应该是另一个 .txt 文件,格式如下: (脚本可以是 bash 或 perl 或任何其他脚本语言)
- city-01-r-01 在 ___(分钟)____(秒)内无法访问 ____(日期)
- city-02-r-01 在 ___(分钟)____(秒)内无法访问 ____(日期)
我今天在谷歌上搜索了一下,发现我需要使用 IFS(用于逐行阅读)和 while/do 循环来实现这一点。但是,我不确定如何实现结果。
有很多方法可以用 perl、python、SQLite、C、C++、java、tcl、bash...这里是 GNU awk,用于文本文件处理的 GNU 瑞士刀:
$ cat csv2ts.awk
BEGIN { FS = ";" }
{
t = ;
gsub(/[-:]/, " ", t);
t = mktime(t);
}
== "UNKNOWN" || == "CRITICAL" { c[] = t }
== "OK" {
d = t - c[];
printf("%s was unreachable for %d (minutes) %d (seconds) on %s (date)\n",
, d / 60, d % 60, strftime("%F", t));
}
$ awk -f csv2ts.awk data.csv > data.txt
$ cat data.txt
city-01-r-01 was unreachable for 14 (minutes) 55 (seconds) on 2015-08-02 (date)
city-02-r-01 was unreachable for 5 (minutes) 59 (seconds) on 2015-08-03 (date)
awk 脚本存储在文件 csv2ts.awk
中,您的原始数据在 data.csv
中,输出结果在 data.txt
中。 awk 脚本使用';'作为字段分隔符 (FS = ";"
)。它使用第一个字段 (gsub
、mktime
) 计算每条记录的时间戳(以秒为单位)。它构建了一个由客户位置(字段#2)索引的时间戳数组(c
)。事件日期是使用 strftime
根据第二个事件 (OK
) 的时间戳计算得出的。剩下的应该很容易理解了。
请注意您的问题未明确说明:
- C市的记录在文件中是连续的吗?
- 您希望日期的确切输出格式是什么?
- 当不可访问时间跨过天数边界时会发生什么?
- 如果对于给定的位置,事件的顺序不是“未知、正常”或“严重”、“正常”,而是其他任何情况,例如“正常”、“正常”或“未知、严重”?
- 如果对于给定位置,第一个事件正常怎么办?
- 如果对于给定位置,最后一个事件不正常怎么办?
如果您完成规范,调整 awk 脚本应该相当容易。
使用 Perl 非常简单 Time::Piece and Time::Seconds。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my %outages;
my $time_format = '%Y-%m-%d %H:%M:%S';
while (<DATA>) {
chomp;
my ($timestamp, $city, $status) = split /;/;
my $time = Time::Piece->strptime($timestamp, $time_format);
if ($status ne 'OK') {
$outages{$city} = $time;
} else { # status is now ok
my $duration = $time - $outages{$city};
say "city $city was unreachable for ",
$duration->pretty, ' on ', $outages{$city}->date;
}
}
__END__
2015-08-02 07:18:30;city-01-r-01;UNKNOWN
2015-08-02 07:33:25;city-01-r-01;OK
2015-08-03 12:56:50;city-02-r-01;CRITICAL
2015-08-03 13:02:49;city-02-r-01;OK
(为简单起见,我将数据放在 DATA
文件句柄中。修复它以从外部文件读取数据留作 reader 的练习。)