数组问题的perl散列
perl hash of arrays issue
我的数组 @lines
中只有几行,其中 *
显示命令的开始时间(如 sync/fetch)和具有相同进程 ID 的行 pid
而没有 *
的命令会显示结束时间。它们可能并不总是连续的。我想获得特定 processID
和 cmd
的 startdate
和 enddate
。与 usera
一样,进程 ID 11859
的 cmd sync
开始于 2015/01/13 13:53:01.491-05:00
并结束于 2015/01/13 13:55:01.492-05:00
下面是我采用数组散列并使用 processID
作为键并拆分行的方法。仅当命令的开始行和结束行是连续的时,这才能正常工作,但即使它们不连续,我如何才能使它工作。
my %users;
foreach my $line (@lines) {
if ($line =~ m{(\*)+}) {
($stdate, $sttime, $pid, $user, $cmd) = split ' ', $line;
$startdate ="$stdate $sttime";
}
else {
($eddate, $edtime, $pid, $user, $cmd) = split ' ', $line;
$enddate = "$eddate $edtime";
}
$users{$pid} = [ $startdate, $enddate, $user, $cmd ];
}
@lines
中的内容:
2015/01/13 13:53:01.491-05:00 11859 usera *sync_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:57:02.079-05:00 11863 userb *fetch_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:59:02.079-05:00 11863 userb fetch_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:55:01.492-05:00 11859 usera sync_cmd 7f1f9bfff700 10.101.17.111
当您分配给 %users{$pid}
时,您假设最近的 $startdate
和 $enddate
都是相关的。保存字段值的变量的范围大于 foreach
循环,允许这些值在记录之间流血,这一事实加剧了这个问题。
在if
块中,您应该将$startdate, $user, $cmd
的值分配给数组。如果你喜欢,可以单独或作为一片。在 else
块中,您应该将 $enddate
分配给它在数组中的元素。
正则表达式加分项:您似乎并不真正关心记录中是否有 *
,这使得正则表达式中的 +
变得多余。作为一个额外的好处,没有它,捕获组也没有价值。 m{\*}
应该做得很好。
我正在查看您的代码,想知道您为什么要使用数组哈希。
就我而言,数组的用途是一组相似但有序的值。
你能不能改为:
my %processes;
foreach (@lines) {
my ( $date, $time, $pid, $user, $cmd, @everything_else ) = split;
if ( $cmd =~ m/^\*/ ) {
#if command starts with a * - it started.
if ( defined $processes{$pid} ) {
print "WARNING: $pid reused\n";
}
$processes{$pid}{'start_date'} = $date;
$processes{$pid}{'time'} = $time;
$processes{$pid}{'user'} = $user;
$processes{$pid}{'cmd'} = $cmd;
}
else {
#cmd does not start with '*'.
if ( $processes{$pid}{'cmd'} =~ m/$cmd/ ) {
#this works, because 'some_command' is a substring of '*some_command'.
$processes{$pid}{'end_date'} = $date;
$processes{$pid}{'end_time'} = $time;
}
else {
print
"WARNING: $pid has a command of $cmd, where it started with $processes{$pid}{'cmd'}\n";
}
}
}
你可能需要一些额外的验证测试,以防你有,例如足够长的日志,可以重用 pids,或者例如您的日志不包括特定进程的开始和结束。
我的数组 @lines
中只有几行,其中 *
显示命令的开始时间(如 sync/fetch)和具有相同进程 ID 的行 pid
而没有 *
的命令会显示结束时间。它们可能并不总是连续的。我想获得特定 processID
和 cmd
的 startdate
和 enddate
。与 usera
一样,进程 ID 11859
的 cmd sync
开始于 2015/01/13 13:53:01.491-05:00
并结束于 2015/01/13 13:55:01.492-05:00
下面是我采用数组散列并使用 processID
作为键并拆分行的方法。仅当命令的开始行和结束行是连续的时,这才能正常工作,但即使它们不连续,我如何才能使它工作。
my %users;
foreach my $line (@lines) {
if ($line =~ m{(\*)+}) {
($stdate, $sttime, $pid, $user, $cmd) = split ' ', $line;
$startdate ="$stdate $sttime";
}
else {
($eddate, $edtime, $pid, $user, $cmd) = split ' ', $line;
$enddate = "$eddate $edtime";
}
$users{$pid} = [ $startdate, $enddate, $user, $cmd ];
}
@lines
中的内容:
2015/01/13 13:53:01.491-05:00 11859 usera *sync_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:57:02.079-05:00 11863 userb *fetch_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:59:02.079-05:00 11863 userb fetch_cmd 7f1f9bfff700 10.101.17.111
2015/01/13 13:55:01.492-05:00 11859 usera sync_cmd 7f1f9bfff700 10.101.17.111
当您分配给 %users{$pid}
时,您假设最近的 $startdate
和 $enddate
都是相关的。保存字段值的变量的范围大于 foreach
循环,允许这些值在记录之间流血,这一事实加剧了这个问题。
在if
块中,您应该将$startdate, $user, $cmd
的值分配给数组。如果你喜欢,可以单独或作为一片。在 else
块中,您应该将 $enddate
分配给它在数组中的元素。
正则表达式加分项:您似乎并不真正关心记录中是否有 *
,这使得正则表达式中的 +
变得多余。作为一个额外的好处,没有它,捕获组也没有价值。 m{\*}
应该做得很好。
我正在查看您的代码,想知道您为什么要使用数组哈希。
就我而言,数组的用途是一组相似但有序的值。
你能不能改为:
my %processes;
foreach (@lines) {
my ( $date, $time, $pid, $user, $cmd, @everything_else ) = split;
if ( $cmd =~ m/^\*/ ) {
#if command starts with a * - it started.
if ( defined $processes{$pid} ) {
print "WARNING: $pid reused\n";
}
$processes{$pid}{'start_date'} = $date;
$processes{$pid}{'time'} = $time;
$processes{$pid}{'user'} = $user;
$processes{$pid}{'cmd'} = $cmd;
}
else {
#cmd does not start with '*'.
if ( $processes{$pid}{'cmd'} =~ m/$cmd/ ) {
#this works, because 'some_command' is a substring of '*some_command'.
$processes{$pid}{'end_date'} = $date;
$processes{$pid}{'end_time'} = $time;
}
else {
print
"WARNING: $pid has a command of $cmd, where it started with $processes{$pid}{'cmd'}\n";
}
}
}
你可能需要一些额外的验证测试,以防你有,例如足够长的日志,可以重用 pids,或者例如您的日志不包括特定进程的开始和结束。