timestamp : IDs returned
20160420084726:-
20160420085418:[111783178, 111557953, 111646835, 111413356, 111412662, 105618372, 111413557]
20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281]
20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281]
20160420085522:[111344871, 111394583, 111295547, 111379566, 111352520]
20160420090022:[111344871, 111394583, 111295547, 111379566, 111352520]
时间戳的格式为 YYYYMMDDhhmmss
· ads 是用方括号括起来的以逗号分隔的广告资产 ID 列表,或者 - 如果没有返回广告
我需要编写一个脚本,在一天中的每十分钟时间内输出:
返回的 ID 数
返回的唯一 ID 的数量
该脚本应支持命令行参数来选择是否应给出唯一 ID 或总 ID。
使用上述日志摘录的示例输出(在总计模式下):
20160420084:0
20160420085:26
20160420090:5
在独特的计数模式下,它会给出:
20160420084:0
20160420085:19
20160420090:5
这是我到目前为止的情况:
#!/usr/bin/bash
awk -F":" ' { print $1":" $2 } ' file.log | sort -r | uniq -c
结果:
1 20160420090022:[111344871, 111394583, 111295547, 111379566, 111352520]
1 20160420085522:[111344871, 111394583, 111295547, 111379566, 111352520]
1 20160420085418:[111783178, 111557953, 111646835, 111413356, 111412662, 105618372, 111413557]
2 20160420085418:[111413432, 111633904, 111783198, 111792767, 111557948, 111413225, 111413281]
1 20160420084726:-
7: –
答案1
使用 GNU awk 处理数组数组(length(array)
但现在大多数 awk 都这样做):
$ cat tst.awk
BEGIN { FS=OFS=":" }
NR>1 {
time = substr($1,1,11)
totIds[time] += 0
if ( gsub(/[][ ]/,"",$2) ) {
totIds[time] += split($2,ids,/,/)
for ( i in ids ) {
unqIds[time][ids[i]]
}
}
}
END {
for ( time in totIds ) {
print time, ( type ~ /^tot/ ? totIds[time] : length(unqIds[time]) )
}
}
$ awk -v type='tot' -f tst.awk file
20160420084:0
20160420085:26
20160420090:5
$ awk -v type='unq' -f tst.awk file
20160420084:0
20160420085:19
20160420090:5
如果您没有 GNU awk,您可以使用任何 awk 执行相同的操作,只是代码和内存使用量稍多一些:
$ cat tst.awk
BEGIN { FS=OFS=":" }
NR>1 {
time = substr($1,1,11)
totIds[time] += 0
if ( gsub(/[][ ]/,"",$2) ) {
totIds[time] += split($2,ids,/,/)
for ( i in ids ) {
if ( !seen[time,ids[i]]++ ) {
numUnq[time]++
}
}
}
}
END {
for ( time in totIds ) {
print time, ( type ~ /^tot/ ? totIds[time] : numUnq[time]+0 )
}
}
$ awk -v type='tot' -f tst.awk file
20160420084:0
20160420085:26
20160420090:5
$ awk -v type='unq' -f tst.awk file
20160420084:0
20160420085:19
20160420090:5
答案2
$ cat summarise.pl
#!/usr/bin/perl
use strict;
use List::Util qw(sum0); # useful function to sum elements of array
# handle command-line options
use Getopt::Long qw(VersionMessage :config gnu_getopt);
use Pod::Usage;
$main::VERSION='0.0-alpha';
my $help = 0;
my $type;
GetOptions('total|sum|s|t' => sub { $type .= 't' },
'unique|u' => sub { $type .= 'u' },
'both|b' => sub { $type = 'tu' },
'help|h|?' => \$help,
'version|V' => sub { VersionMessage() },
) or pod2usage(2);
pod2usage(-exitval => 0, -verbose => 2) if $help or (! @ARGV && -t);
$type = 'b' if length($type) > 1;
$type = 'u' if length($type) == 0; # default is unique
# Hash-of-Hashes (HoH) to hold timestamps, ids, and id counts.
# Primary key will be timestamp, secondary keys are the IDs,
# and values are the counts of each secondary key.
my %timestamps;
# read and process input file
while(<<>>) {
next if ($. == 1); # skip first line of input file(s)
chomp;
# remove square brackets and spaces from input line
s/[][]|\s+//g;
# split current line on colon and commas
my($ts,@ids) = split /[:,]/;
$ts = substr($ts,0,11);
$timestamps{$ts} = () unless (defined $timestamps{$ts});
# remove non-numeric elements of @ids array
@ids = grep { /^\d+$/ } @ids;
# Convert to the HoH structure.
map { $timestamps{$ts}{$_}++ } @ids;
close(ARGV) if eof; # reset line counter $. at end of each input file
}
# all input has been processed, so print the results.
foreach my $ts (sort keys %timestamps) {
my $u = scalar keys %{ $timestamps{$ts} };
my $s = sum0 values %{ $timestamps{$ts} };
if ($type eq 'u') {
printf "%s: %i\n", $ts, $u;
} elsif ($type eq 't') {
printf "%s: %i\n", $ts, $s;
} elsif ($type eq 'b') {
printf "%s: %i, %i\n", $ts, $u, $s;
};
}
__END__
=head1 summarise.pl
Script for counting and summarising Numbers & Unique numbers in each line.
=head1 SYNOPSIS
summarise.pl [options] [file ...]
=head1 OPTIONS
=over
=item B<--total>
print total number of IDs per timestamp
=item B<--unique>
print number of unique IDs per timestamp
=item B<--both>
print both unique and total number of IDs
=item B<--version>
Print script's version and exit
=item B<--help>
Print this help message and exit
=back
=cut
笔记:列表::实用程序,Pod::用法, 和Getopt::长都是核心 Perl 模块并且包含在 Perl 中。
perldoc pod
有关 perl 的“Plain Old Documentation”内置代码文档如何工作的详细信息,请参阅参考资料。我仅仅触及了它的功能的表面。
示例输出:
$ ./summarise.pl input.txt
20160420084: 0
20160420085: 19
20160420090: 5
$ ./summarise.pl input.txt -t
20160420084: 0
20160420085: 26
20160420090: 5
$ ./summarise.pl input.txt -b
20160420084: 0, 0
20160420085: 19, 26
20160420090: 5, 5
$ ./summarise.pl --version
./summarise.pl version 0.0-alpha
(Getopt::Long::GetOptions version 2.51; Perl version 5.32.1)
$ ./summarise.pl --help
summarise.pl
Script for counting and summarising Numbers & Unique numbers in each
line.
SYNOPSIS
summarise.pl [options] [file ...]
OPTIONS
--total, --sum, -t, -s
print total number of IDs per timestamp
--unique, -u
print number of unique IDs per timestamp
--both, -b
print both unique and total number of IDs
--version, -V
Print script's version and exit
--help, -h, -?
Print this help message and exit
getopt_long()
顺便说一句,就像许多 C 程序使用的GNU函数一样,perlGetopt::Long
模块理解选项的缩写 - 例如--uni
、--uniq
、等将被视为与或-un
相同。只要缩写足够长,能够明确地对应于选项名称,它就可以工作。-u
--unique
而且,如果您想知道%timestamps
散列数据结构“是什么样子”:
{
"20160420084" => undef,
"20160420085" => {
105618372 => 1, 111295547 => 1, 111344871 => 1, 111352520 => 1, 111379566 => 1,
111394583 => 1, 111412662 => 1, 111413225 => 2, 111413281 => 2, 111413356 => 1,
111413432 => 2, 111413557 => 1, 111557948 => 2, 111557953 => 1, 111633904 => 2,
111646835 => 1, 111783178 => 1, 111783198 => 2, 111792767 => 2,
},
"20160420090" => {
111295547 => 1, 111344871 => 1, 111352520 => 1, 111379566 => 1, 111394583 => 1
},
}
哈希的哈希是一个关联数组(“哈希”),其中每个元素也可以是哈希。
perldoc perldsc
有关 perl 数据结构的详细信息,请参阅参考资料。