我正在使用 Bash shell 处理一些日志文件,需要将其放入 CSV 文件中。我需要的信息是流程开始日期和时间, 流程结束日期和时间,进程 ID和信息
我所做的是,grep 包括启动进程的行并将它们放入一个文件中,然后 Grep 结束进程并将它们放入第二个文件中。完成后,我获取每个文件,并使用 awk 拆分和提取所需的信息,下面是我正在使用的代码,
input=starts.txt
while IFS= read -r line
do
procs=`echo $line | awk '{ print $6;}'
date_s=`echo $line | awk '{ print $1;}'`
time_s=`echo $line | awk '{ print $2;}'`
m1=`echo $line | awk '{ print $3;}'`
m2=`echo $line | awk '{ print $4;}'`
m3=`echo $line | awk '{ print $5;}'`
m4=`echo $line | awk '{ print $7;}'`
m5=`echo $line | awk '{ print $8;}'`
m6=`echo $line | awk '{ print $9;}'`
echo $procs ";" $date_s ";" $time_s ";" $m1 $m2 $m3 $m4 $m5 $m6
one < "$input" > result.csv
这些行具有以下格式:
02/01/2018 10:32:35 ANR4930I Reclamation process 1320 started for primary storage pool VM_VTL_POOL automatically, threshold=75, duration=None. (PROCESS: 1320)
我现在有两个问题:
- while 循环没有结束。
- 提取时间/日期和进程 ID 后,我想将剩余的消息放在单独的字段中,而不是逐字逐句地进行并连接它们(m1 m2 m 3 ...)此外,如果我的代码可以进行任何改进。
答案1
最大的改进是完全避免使用 shell 循环,直接在 Awk 中处理每条记录(行)。例如:
$ awk '{
printf("%s;%s;%s;", $6, $1, $2)
for(i=3; i<NF;i++) {
if(i==6) continue;
printf("%s ", $i)
}
printf("%s\n",$NF)
}' input
1320;02/01/2018;10:32:35;ANR4930I Reclamation process started for primary storage pool VM_VTL_POOL automatically, threshold=75, duration=None. (PROCESS: 1320)
答案2
我理解你的任务是“将字段 5(process number
)移到前面,然后输出以 分隔的前 3 个字段;
,接着是,;
然后是余数。
在 Perl 中我会这样做(作为一行代码):
perl -a -n -l -e \
'unshift @F, splice(@F, 5, 1);
print join(";", @F[0..2]), ";@F[3..$#F]";' \
< input.txt > output.csv
结果:
input.txt
:
02/01/2018 10:32:35 ANR4930I Reclamation process 1320 started for primary storage pool VM_VTL_POOL automatically, threshold=75, duration=None. (PROCESS: 1320)
02/01/2018 10:32:35 ANR4930I Reclamation process 4567 started for primary storage pool VM_VTL_POOL automatically, threshold=75, duration=None. (PROCESS: 1320)
output.csv
:
1320;02/01/2018;10:32:35;ANR4930I Reclamation process started for primary storage pool VM_VTL_POOL automatically, threshold=75, duration=None. (PROCESS: 1320)
4567;02/01/2018;10:32:35;ANR4930I Reclamation process started for primary storage pool VM_VTL_POOL automatically, threshold=75, duration=None. (PROCESS: 1320)
解释:
perl -a -n -l -e
- 在空格处拆分每个输入行,并将结果放入预定义数组中
@F
- 处理每个输入行(但不要打印)
- 使用输入分隔符(
\n
)作为输出分隔符(相当简化) - 对每个输入行运行以下表达式
unshift @F, splice(@F, 5, 1);
- 从数组 (包含在空格处分割的输入文件的一行)中删除第 5个元素(count=1),并将该第 5个元素添加到数组前面。
@F
@F
print join(";", @F[0..2]), ";@F[3..$#F]";'
@F
打印介于;
两者之间的前 2 个元素,然后- 后面跟着一个文字,然后 是从第 3 个元素开始到最后
;
数组的其余部分,以空格作为分隔符。(打印用空格分隔的项目。)@F
print "@any_array"
如果您想要与脚本相同的代码(例如format-messages.pl
),那么它看起来会略有不同,因为命令行切换到 Perl(现在缺失)隐式添加了一些现在必须明确添加的代码。(是的,有是其他方式,但是...)
#!/usr/bin/env perl
use strict;
use warnings;
while(<>) {
my @F = split;
unshift @F, splice(@F, 5, 1);
print join(";", @F[0..2]), ";@F[3..$#F]\n";
}
执行 achmod +x format-messages.pl
然后运行此脚本./format-messages.pl < input.txt > output.csv