perl,awk解析日志文件

时间:2018-07-24 15:21:45

标签: perl logging awk

有人可以帮助我使用日志文件将其从垂直转换为水平吗?

我有这个file1.txt

Time: 2018070515
timezone: CEST
Client: 192.168.205.132
Subscriber: 345896546
proxyIP: 100.24.201.102
device: Android

Time: 2018070516
timezone: CEST
Client: 192.168.205.134
Subscriber: 345777546
proxyIP: 100.24.202.102
device: Android

Time: 2018070516
timezone: CEST
Start: 1530
Client: 192.168.204.112
Subscriber: 345898646
proxyIP: 100.24.202.102
device: Android

Time: 2018070517
timezone: CEST
Start: 1530
Client: 192.168.205.137
Subscriber: 345897466
proxyIP: 100.24.201.102
device: IPhone

我需要以这种方式使用它们:

2018070515,192.168.205.132,345896546,Android
2018070516,192.168.205.134,345777546,Android
2018070516,192.168.204.112,345898646,Android
2018070517,192.168.205.137,345897466,IPhone

行数并不重要,我知道它们以时间开头。

感谢您提供给定的解决方案。但是我的文件日志中有超过100000行,而我尝试给出的任何解决方案都会产生mi错误输出。当我使用文件作为此处的示例时,命令起作用。

5 个答案:

答案 0 :(得分:3)

这是Perl的一个内衬纸

perl -an00E 'BEGIN{ $" = "," } %F = @F; say "@F{qw(Time: Client: Subscriber: device:)}"' <./file.txt

-00使用空白行作为输入记录分隔符来读取文件

-n遍历文件中的每个记录

-a自动将记录拆分为@F

然后代码从@F进行哈希处理,并打印出已设置$"以便将,插入插值数组或切片的每个元素之间的所需记录

请注意,这是假设数据中没有空格

答案 1 :(得分:2)

您可以将数据像YAML一样对待,因为它们是用冒号:分隔的简单键/值对。

此Perl解决方案将输入记录分隔符$/设置为两个新行(此处假定Linux行结尾),并将每个记录视为实际记录。然后它将使用Perl's YAML parser将其转换为哈希引用,然后您可以有选择地将其添加到CSV文件中。

use v5.10; # strict, warnings, feature 'say'
use YAML 'Load';

local $/ = "\n\n";
while (my $record = <DATA>) {
    my $fields = Load($record);
    say join ',', @$fields{qw/Time Client Subscriber device/};
}

__DATA__
Time: 2018070515
timezone: CEST
Client: 192.168.205.132
Subscriber: 345896546
proxyIP: 100.24.201.102
device: Android

Time: 2018070516
timezone: CEST
Client: 192.168.205.134
Subscriber: 345777546
proxyIP: 100.24.202.102
device: Android

如果您的记录可能不包含所有必填字段,则可以使用mapdefined-or operator //来获取空字符串。

say join ',', map { $foo->{$_} // q{} } qw/Time Client Subscriber device/; 

此解决方案至少需要say的Perl 5.10。

它可以轻松转换为单线。

$ perl -MYAML -nE 'BEGIN { $/ = "\n\n" } $f = Load($_); say join ",", @$f{qw/Time Client Subscriber device/}' <inputfile

请注意,您可能需要从CPAN安装YAML。

答案 2 :(得分:0)

您可以尝试以下awk命令:

awk -v RS= 'BEGIN{r["Time:"];r["Client:"];r["Subscriber:"];r["device:"]}
    {for(i = 1; i <= NF; i+=2) {
       if($i in r) {
           if(i != NF-1) {f=","} else {f=""} printf "%s%s" ,$(i+1),f
       }
     }
     print ""
    }' file1.txt

使用的选项

  • -v RS=:转换记录中的每个段落。
  • r:是具有所需字段的数组。
  • forif($1 in r):遍历字段,如果字段ir中,则打印它。
  • if(i!=NF)else仅用于格式化。

编辑

仅在value仅包含一个字符串时有效。

答案 3 :(得分:0)

perl -00 -nE '$text = $_; say join ",", map {$text =~ /$_: (.*)/} qw<Time Client Subscriber device>' file1.txt

答案 4 :(得分:0)

只需创建一个将每个标签/名称映射为其值的数组,然后每当您敲空白行或文件末尾时,请打印您感兴趣的先前记录中标签的值:

$ cat tst.awk
NF {
    tag = val = $0
    sub(/:.*/,"",tag)
    sub(/^[^:]+: */,"",val)
    f[tag] = val
    next
}
{ prt() }
END { prt() }
function prt() {
    OFS = ","
    print f["Time"], f["Client"], f["Subscriber"], f["device"]
    delete f
}

$ awk -f tst.awk file
2018070515,192.168.205.132,345896546,Android
2018070516,192.168.205.134,345777546,Android
2018070516,192.168.204.112,345898646,Android
2018070517,192.168.205.137,345897466,IPhone

以上内容可在任何UNIX盒中的任何shell中使用任何awk进行工作。