有人可以帮助我使用日志文件将其从垂直转换为水平吗?
我有这个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错误输出。当我使用文件作为此处的示例时,命令起作用。
答案 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
如果您的记录可能不包含所有必填字段,则可以使用map
和defined-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
:是具有所需字段的数组。for
和if($1 in r)
:遍历字段,如果字段i
在r
中,则打印它。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进行工作。