解析默认的Salt高态输出

时间:2019-05-17 00:30:44

标签: regex perl awk grep salt

我试图解析Salt的高状态输出已被证明是困难的。由于我仍然希望输出清晰易读,因此无需将输出更改为json

将“摘要”转换为机器可读内容的最佳方法是什么?

Summary for app1.domain.com
--------------
Succeeded: 278 (unchanged=12, changed=6)
Failed:      0
--------------
Total states run:     278
Total run time:     7.383 s
--
Summary for app2.domain.com
--------------
Succeeded: 278 (unchanged=12, changed=6)
Failed:      0
--------------
Total states run:     278
Total run time:     7.448 s
--
Summary for app0.domain.com
--------------
Succeeded: 293 (unchanged=13, changed=6)
Failed:      0
--------------
Total states run:     293
Total run time:     7.510 s

没有更好的主意,我试图grep和awk输出并将其插入到csv中。

这两个作品:

cat ${_FILE} | grep Summary | awk '{ print $3} ' | \
    tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate.csv;

cat ${_FILE} | grep -oP '(?<=unchanged=)[0-9]+' | \
    tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate.csv;

但是这个失败了,但是可以在Reger

下工作
cat ${_FILE} | grep -oP '(?<=\schanged=)[0-9]+' | \
    tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate.csv;

EDIT1:@vintnes @ikegami我同意我更愿意使用json输出来解析输出,但是Salt输出到josn时不会提供更改摘要。到目前为止,这是我所拥有的,虽然非常难看,但是它正在工作。

cat ${_FILE} | grep Summary | awk '{ print $3} ' | \
    tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate_tmp.csv;

cat ${_FILE} | grep -oP '(?<=unchanged=)[0-9]+' | \
    tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate_tmp.csv;

cat ${_FILE} | grep unchanged | awk -F' ' '{ print $4}' | \
    grep -oP '(?<=changed=)[0-9]+' | tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate_tmp.csv;

cat ${_FILE} | { grep "Warning" || true; } | awk -F: '{print $2+0} END { if (!NR) print "null" }' | \
    tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate_tmp.csv;

cat ${_FILE} | { grep "Failed" || true; } | awk -F: '{print $2+0} END { if (!NR) print "null" }' | \
    tr '\n' ',' | sed '$s/,$/\n/' >> /tmp/highstate_tmp.csv;

csvtool transpose /tmp/highstate_tmp.csv > /tmp/highstate.csv;

sed -i '1 i\instance,unchanged,changed,warning,failed' /tmp/highstate.csv;

输出:

instance,unchanged,changed,warning,failed
app1.domain.com,12,6,,0
app0.domain.com,13,6,,0
app2.domain.com,12,6,,0

3 个答案:

答案 0 :(得分:2)

perl -e'
   use strict;
   use warnings qw( all );

   use Text::CSV_XS qw( );

   my $csv = Text::CSV_XS->new({ auto_diag => 2, binary => 1 });
   $csv->say(select(), [qw( instance unchanged change warning failed )]);

   my ( $instance, $unchanged, $changed, $warning, $failed );
   while (<>) {
      if (/^Summary for (\S+)/) {
         ( $instance, $unchanged, $changed, $warning, $failed ) = $1;
      }
      elsif (/^Succeeded:\s+\d+ \(unchanged=(\d+), changed=(\d+)\)/) {
         ( $unchanged, $changed ) = ( $1, $2 );
      }
      elsif (/^Warning:\s+(\d+)/) {
         $warning = $1;
      }
      elsif (/^Failed:\s+(\d+)/) {
         $failed = $1;
         $csv->say(select(), [ $instance, $unchanged, $changed, $warning, $failed ]);
      }
   }
'

通过STDIN提供输入,或提供从中读取作为参数的文件的路径。


Terse版本:

perl -MText::CSV_XS -ne'
   BEGIN {
      $csv = Text::CSV_XS->new({ auto_diag => 2, binary => 1 });
      $csv->say(select(), [qw( instance unchanged change warning failed )]);
   }
   /^Summary for (\S+)/ and @row=$1;
   /^Succeeded:\s+\d+ \(unchanged=(\d+), changed=(\d+)\)/ and @row[1,2]=($1,$2);
   /^Warning:\s+(\d+)/ and $row[3]=$1;
   /^Failed:\s+(\d+)/ and ($row[4]=$1), $csv->say(select(), \@row);
'

答案 1 :(得分:1)

您在这里。如果您的输出包含警告,这也将起作用。请注意,输出的顺序与您指定的顺序不同。这是每个记录在文件中出现的顺序。如有任何疑问,请不要犹豫。

$ awk -v OFS=, '
        BEGIN        { print "instance,unchanged,changed,warning,failed" }
        /^Summary/   { instance=$NF }
        /^Succeeded/ { split($3 $4 $5, S, /[^0-9]+/) }
        /^Failed/    { print instance, S[2], S[3], S[4], $2 }
' "$_FILE"
  • split($3 $4 $5, S, /[^0-9]+/)通过忽略前两个“单词” Succeeded: ###并使用任意数量的非数字作为分隔符来处理警告的可能性。

编辑:打印在/^Fail/上,而不使用/^Summ/END

答案 2 :(得分:0)

改进@vintnes的答案。 以制表符分隔的CSV格式输出

编写awk脚本,该脚本按行顺序从行中读取值。 在读取记录时将其打印。

script.awk

BEGIN {print("computer","succeeded","unchanged","changed","failed","states run","run time");}
FNR%8 == 1 {arr[1] = $3}
FNR%8 == 3 {arr[2] = $2; arr[3] = extractNum($3); arr[4] = extractNum($4)}
FNR%8 == 4 {arr[5] = $2;}
FNR%8 == 6 {arr[6] = $4;}
FNR%8 == 7 {arr[7] = $4; print arr[1],arr[2],arr[3],arr[4],arr[5],arr[6],arr[7];}

function extractNum(str){match(str,/[[:digit:]]+/,m);return m[0];}

运行脚本

制表符分隔的CSV输出

awk -v OFS="\t" -f script.awk input-1.txt input-2.txt ...

逗号分隔的CSV输出

awk -v OFS="," -f script.awk input-1.txt input-2.txt ...

输出

computer        succeeded       unchanged        changed failed  states run      run time
app1.domain.com 278     12      6       0       278     7.383
app2.domain.com 278     12      6       0       278     7.448
app0.domain.com 293     13      6       0       293     7.510

computer,succeeded,unchanged,changed,failed,states run,run time
app1.domain.com,278,12,6,0,278,7.383
app2.domain.com,278,12,6,0,278,7.448
app0.domain.com,293,13,6,0,293,7.510

说明

BEGIN {print("computer","succeeded","unchanged","changed","failed","states run","run time");}

打印标题CSV行

FNR%8 == 1 {arr[1] = $3}

从第3行(第8行中的第1行)中提取arr [1]值

FNR%8 == 3 {arr[2] = $2; arr[3] = extractNum($3); arr[4] = extractNum($4)}

从(8行中的第三行)的第二,第三,第四字段中提取arr [2,3,4]值

FNR%8 == 4 {arr[5] = $2;}

从(8行的第4行)的第2字段中提取arr [5]值

FNR%8 == 6 {arr[6] = $4;}

从第4个字段(第8行第6行)中提取arr [6]值

FNR%8 == 7 {arr[7] = $4;

从(第8行中的第7行)第4字段中提取arr [7]值

print arr[1],arr[2],arr[3],arr[4],arr[5],arr[6],arr[7];}

从8行中读取第7行后,打印提取的变量的数组元素。

function extractNum(str){match(str,/[[:digit:]]+/,m);return m[0];}

从文本字段中提取数字的实用程序功能。