【问题标题】:Create a CSV file from a specific log file using shell script使用 shell 脚本从特定日志文件创建 CSV 文件
【发布时间】:2018-02-16 22:02:40
【问题描述】:

我正在尝试使用 Linux 中的 sed、awk、粘贴命令将特定日志文件转换为 CSV 文件,以便能够使用 gnuplot 或 MS Excel 对其进行绘图。但是,我无法以我想要的方式做到这一点。这是示例日志文件:

Feb 15 13:57:08 Program1: The pool size: 100 [High: 80 Norm: 20 Low: 0]
Feb 15 13:58:53 Program1: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 13:58:54 Program3: The pool size: 200 [High: 0 Norm: 200 Low: 0]
Feb 15 13:58:56 Program4: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 13:58:58 Program1: The pool size: 200 [High: 0 Norm: 200 Low: 0]
Feb 15 13:58:59 Program5: The pool size: 300 [High: 100 Norm: 200 Low: 0]
Feb 15 13:59:05 Program1: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 14:00:11 Program2: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 14:00:12 Program2: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 14:00:13 Program1: The pool size: 200 [High: 0 Norm: 200 Low: 0]
Feb 15 14:00:16 Program4: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 14:00:17 Program2: The pool size: 100 [High: 50 Norm: 50 Low: 0]
Feb 15 14:02:28 Program5: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 14:02:31 Program1: The pool size: 100 [High: 0 Norm: 100 Low: 0]
Feb 15 14:11:01 Program1: The pool size: 100 [High: 0 Norm: 100 Low: 0]

我正在尝试将上述数据转换为 CSV 文件,以便在特定时间点获得数据。我期望的输出 CSV 应该是以下格式:

TimeStamp,Program1_Total,Program1_High,Program1_Norm,Program1_Low,Program2_Total,Program2_High,Program2_Norm,Program2_Low,Program3_Total,Program3_High,Program3_Norm,Program3_Low,Program4_Total,Program4_High,Program4_Norm,Program4_Low

Feb 15 13:57:08,100,80,20,0,0,0,0,0,0,0,0,0,0,0,0,0
Feb 15 13:58:53,100,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0
...
...

我尝试了什么?

我尝试对特定程序进行 grepping,并通过以下方式创建特定于该程序的单独较小文件:

grep "Program1" sample.log > Program1.log
grep "Program2" sample.log > Program2.log

我尝试使用粘贴命令加入他们。但是,我无法弄清楚如何以更好的方式处理这些时间戳。

任何帮助将不胜感激。提前致谢。

【问题讨论】:

  • 到目前为止你尝试过什么?您有正在编写的示例脚本吗?
  • 您需要在输出中更加具体。看起来您希望将不同的行合并为一行。但是所有这些行的“TimeStamp”都不同,你期望什么?
  • @StefanM 我希望日志文件中存在的每个唯一时间戳都有一个唯一行。如果您当时没有该程序的任何数据,请对该程序的数据填零。
  • 请更改输入数据,然后。因为您没有重复的时间戳,所以结果不会令人满意。仍然:到目前为止,您尝试过什么?
  • @StefanM 可能有也可能没有重复的时间戳。假设是这样。我怎样才能做到这一点?

标签: linux bash awk sed


【解决方案1】:

我想我为您的任务找到了一个 1 班轮解决方案,它只使用 shell 和 awk,但请注意,它一点也不漂亮,您需要事先将标头添加到输出文件中:

echo "TimeStamp,P1_Total,P1_High,P1_Norm,P1_Low,P2_Total,P2_High,P2_Norm,P2_Low,P3_Total,P3_High,P3_Norm,P3_Low,P4_Total,P4_High,P4_Norm,P4_Low,P5_Total,P5_High,P5_Norm,P5_Low" >> final_output.txt

for i in `seq 1 5` 
do 
l=$((i-1))
r=$((5-i))
awk -v left_padd=${l} -v right_padd=${r} -v nb=${i} '{gsub(/]/, "", $14)} {if ($4 ~ "Program" nb) {printf $1" "$2" "$3", "; for(a=0;a<left_padd;a++) printf "0,\t 0,\t 0,\t 0,\t "; printf $8",\t "$10",\t "$12",\t "$14",\t "; for(b=0;b<right_padd;b++) printf "0,\t 0,\t 0,\t 0,\t "; print "\n"} }' sample.log
done >> final_output.txt

*** 请注意,您必须将seq 1 5 中的5 更改为您希望在输出文件中包含的Program# 条目数,我在您的示例中使用了5。此外,您还需要将r=$((5-i)) 中的5 更改为相同的值。

解释:

  • for 循环每次都通过文件搜索Program# 使用awk 输入。
  • l 变量计算它应该在左侧添加多少个 0 值 你的桌子。
  • r 变量与l 值相同,只是它添加了 0 个值 向右。
  • nb 变量存储Program #,所以awk 部分知道 它应该在输入文件中查找哪些行。
  • awk 仅打印出您在输入中要求的值 每个 Program# 条目的文件以及前面和尾随 表中其他条目的0 值(每个0s 4 个Program#)。

编辑:

我使用\t 来分隔awk 中的值,这样更容易阅读,但您可以删除它,这样您就只有逗号分隔的值。 出于同样的原因,我还将您的答案中的标题约定从Program#_Total 更改为P#_Total。

*我确实意识到这根本不是最优的,因为每个Program# 条目都会多次解析文件,而且您还需要自己在输出文件中添加标题,但这是我能想到的最好的与。

【讨论】:

  • 我不得不在这里和那里做一些改变才能让它为我工作。但这对我制定解决方案有很大帮助。因此,将此答案标记为已接受。
【解决方案2】:

通过使用空格作为分隔符来使用剪切,然后只保留您需要的字段。完成后,使用 sed 将空格替换为逗号。

cut -d ' ' -f 1,2,3,8,10,12,14 && sed 's/ /,/g'

通过使用 while .. read 循环,您可以在每一行中对其进行迭代。

【讨论】:

    【解决方案3】:

    如果 Perl 在选项中,如何:

    #!/bin/bash
    
    perl -e '
    while (<>) {
        if (/^(.{15}) Program(\d+): The pool size: (\d+) \[High: (\d+) Norm: (\d+) Low: (\d+)\]$/) {
            $timestamp = $1;
            $program = $2;
            $size = $3;
            $high = $4;
            $norm = $5;
            $low = $6;
            if (! defined $array{$timestamp}) {
                # it takes care of duplicate timestamps
                push(@timestamps, $timestamp);
            }
            $i = ($program - 1) * 4;
            @{$array{$timestamp}}[$i .. $i + 3] = ($size, $high, $norm, $low);
        }
    }
    foreach (@timestamps) {
        print "$_,", join(",", map {$_ + 0} @{$array{$_}}[0 .. 15]), "\n";
    }' logfile
    

    顺便说一句,您想要的结果中似乎排除了 Program5。如果要包含它,只需将倒数第二行的数字 15 修改为 19 即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      相关资源
      最近更新 更多