我试图解析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
答案 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脚本,该脚本按行顺序从行中读取值。 在读取记录时将其打印。
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];}
从文本字段中提取数字的实用程序功能。