将输出从命令或文件转换为json

时间:2014-12-05 12:02:38

标签: json perl shell

我的脚本提供以下outout,我需要将其转换为json结构。通过Perl或AIX上的其他转换是我想要的路径的一部分。现在我正在阅读大量文档并进行试验(=迄今为止没有成功)..

感谢任何帮助/指示: - )

TEST                            STATUS          FAIL REASON
----                            ------          -----------
Security Profile                PASS            
Group Check                     FAIL            Errors detected in group definition files
User Check                      FAIL            Errors detected in user definition files
Service hostmibd                FAIL            Active
Service aixmibd                 FAIL            Active
Subserver shell                 FAIL            Active
Subserver kshell                FAIL            Active
Subserver login                 FAIL            Active
Subserver exec                  FAIL            Active
Subserver bootps                FAIL            Active
Subserver tftp                  FAIL            Active
Subserver ntalk                 FAIL            Active
SNMP version                    FAIL            snmpdv3ne
SNMP community                  PASS            
SSHD status                     PASS            

2 个答案:

答案 0 :(得分:3)

该程序从DATA文件句柄读取样本数据,并从中构建JSON数据结构。

通过检查标题下方的连字符行来确定每列中数据的位置。使用unpack从每一行提取字段以及从这些位置派生的模板。

JSON模块用于通过将结果转换为Perl数据结构来测试结果,结果使用Data::Dump转储。

支持嵌入数据中的双引号。

希望您能够修改此代码以从您想要的输入文件而不是DATA中读取,并使用生成的JSON数据执行任何操作。

use strict;
use warnings;
use 5.014;    # For non-destructive tr/// and s///

my $headers = <DATA>;
my $dashes = <DATA>;
my @offsets;
push @offsets, $-[0] while $dashes =~ /-+/g;

my @widths = map { $offsets[$_]-$offsets[$_-1] } 1 .. $#offsets;
push @widths, '*';
my $unpack = join ' ', map "A$_", @widths;

my @headers = map { lc =~ tr/ /_/r } unpack $unpack, $headers;

my @lines;

while (<DATA>) {
  next unless /\S/;
  my @fields = map s/"/\\"/gr, unpack $unpack, $_;
  push @lines, '  {' . join(', ', map qq{"$headers[$_]":"$fields[$_]"}, 0 .. $#fields). '}';
}

my $json = "[\n" . join(",\n", @lines) . "\n]\n";

print $json, "\n\n";

use JSON;
use Data::Dump;
dd from_json $json;


__DATA__
TEST                            STATUS          FAIL REASON
----                            ------          -----------
Security Profile                PASS            
Group Check                     FAIL            Errors detected in group definition files
User Check                      FAIL            Errors detected in user definition files
Service hostmibd                FAIL            Active
Service aixmibd                 FAIL            Active
Subserver shell                 FAIL            Active
Subserver kshell                FAIL            Active
Subserver login                 FAIL            Active
Subserver exec                  FAIL            Active
Subserver bootps                FAIL            Active
Subserver tftp                  FAIL            Active
Subserver ntalk                 FAIL            Active
SNMP version                    FAIL            snmpdv3ne
SNMP community                  PASS            
SSHD status                     PASS            

输出JSON

[
  {"test":"Security Profile", "status":" PASS", "fail_reason":""},
  {"test":"Group Check", "status":"FAIL", "fail_reason":"Errors detected in group definition files"},
  {"test":"User Check", "status":"FAIL", "fail_reason":"Errors detected in user definition files"},
  {"test":"Service hostmibd", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Service aixmibd", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Subserver shell", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Subserver kshell", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Subserver login", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Subserver exec", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Subserver bootps", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Subserver tftp", "status":"FAIL", "fail_reason":"Active"},
  {"test":"Subserver ntalk", "status":"FAIL", "fail_reason":"Active"},
  {"test":"SNMP version", "status":"FAIL", "fail_reason":"snmpdv3ne"},
  {"test":"SNMP community", "status":"PASS", "fail_reason":""},
  {"test":"SSHD status", "status":"PASS", "fail_reason":""}
]

输出Perl数据

[
  { fail_reason => "", status => " PASS", test => "Security Profile" },
  {
    fail_reason => "Errors detected in group definition files",
    status => "FAIL",
    test => "Group Check",
  },
  {
    fail_reason => "Errors detected in user definition files",
    status => "FAIL",
    test => "User Check",
  },
  { fail_reason => "Active", status => "FAIL", test => "Service hostmibd" },
  { fail_reason => "Active", status => "FAIL", test => "Service aixmibd" },
  { fail_reason => "Active", status => "FAIL", test => "Subserver shell" },
  { fail_reason => "Active", status => "FAIL", test => "Subserver kshell" },
  { fail_reason => "Active", status => "FAIL", test => "Subserver login" },
  { fail_reason => "Active", status => "FAIL", test => "Subserver exec" },
  { fail_reason => "Active", status => "FAIL", test => "Subserver bootps" },
  { fail_reason => "Active", status => "FAIL", test => "Subserver tftp" },
  { fail_reason => "Active", status => "FAIL", test => "Subserver ntalk" },
  { fail_reason => "snmpdv3ne", status => "FAIL", test => "SNMP version" },
  { fail_reason => "", status => "PASS", test => "SNMP community" },
  { fail_reason => "", status => "PASS", test => "SSHD status" },
]

答案 1 :(得分:0)

固定长度数据始终是unpack的好兆头。 您需要JSON模块进行转换。该程序从STDIN读取并将文件作为参数。

#!/usr/bin/env perl
use warnings;
use strict;
use JSON;

my @names = qw<test status fail_reason>;
my @return;
while(<>){
  next if $. < 3;     # skip the header
  chomp;
  my (%obj);
  @obj{@names} = grep {$_} unpack 'A32A16A*';
  push @return, \%obj;
}

print encode_json \@return;

输出:

[{"status":"PASS","fail_reason":null,"test":"Security Profile"},{"status":"FAIL","test":"Group Check","fail_reason":"Errors detected in group definition files"},{"test":"User Check","fail_reason":"Errors detected in user definition files","status":"FAIL"},{"test":"Service hostmibd","fail_reason":"Active","status":"FAIL"},{"status":"FAIL","test":"Service aixmibd","fail_reason":"Active"},{"test":"Subserver shell","fail_reason":"Active","status":"FAIL"},{"status":"FAIL","fail_reason":"Active","test":"Subserver kshell"},{"status":"FAIL","test":"Subserver login","fail_reason":"Active"},{"fail_reason":"Active","test":"Subserver exec","status":"FAIL"},{"status":"FAIL","test":"Subserver bootps","fail_reason":"Active"},{"fail_reason":"Active","test":"Subserver tftp","status":"FAIL"},{"fail_reason":"Active","test":"Subserver ntalk","status":"FAIL"},{"fail_reason":"snmpdv3ne","test":"SNMP version","status":"FAIL"},{"test":"SNMP community","fail_reason":null,"status":"PASS"},{"test":"SSHD status","fail_reason":null,"status":"PASS"}]

<强>编辑

使用此行可以排除空字段(如果状态为通过,则不会出现失败原因)。

    delete $obj{$_} foreach grep {$obj{$_} eq '' or not defined $obj{$_} keys %obj; 

如果你有更多这样的文件有不同的字段大小,这里有一个提取字段长度的版本:

my (@return, @names, $head_line, $pack_template);
while (<>) {
  chomp;
  if ($. == 1) {      # set the header line
    $head_line = $_;
  }
  elsif($. == 2){
                        # extract the lengths from the second line
    my @lengths = map(length, (/(-+\s*)/g));
    $lengths[-1]= '*';  # replace the last length with * as a catch rest
    $pack_template = join '', map {"A$_"} @lengths;
    @names = unpack $pack_template, $head_line;
  } else {
    my (%obj);
    @obj{@names} = unpack $pack_template;
    push @return, \%obj;
  }
}