Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Parsing output from a 'system' call into objects?

by eval142 (Initiate)
on Feb 21, 2017 at 19:04 UTC ( [id://1182458]=perlquestion: print w/replies, xml ) Need Help??

eval142 has asked for the wisdom of the Perl Monks concerning the following question:

I have a 'system' call to an app

my $test = system($test, "list");

which returns,

p $test CoID: Type: State: ID: ExampleCo A former 97546 ExampleCo B pending 48541 ExampleCo A ready 75521 ExampleCo B former 50123 ExampleCo A contact 60047 ExampleCo B contact 19425 0

I want to select from that output-in-a-variable only the records where Type == "A", and populate the data into an array of objects indexed by ID.

So in effect I want to end up with

array ID = 97546 CoID = ExampleCo State = former ID = 27377 CoID = ExampleCo State = ready ID = 60047 CoID = ExampleCo State = contact

I can print out the `$test` output, but I can't manage to break it apart into object keys & values.

Do I have to save the return into a file, and then parse the file back in?

That seems wasteful, and I think I should be able to work with the data in the returned variable.

What's the right way to break that return data into these objects?

Replies are listed 'Best First'.
Re: Parsing output from a 'system' call into objects?
by huck (Prior) on Feb 21, 2017 at 20:01 UTC

    A more basic example

    use warnings; use strict; #my $testout=`$test list`; my $testout=' CoID: Type: State: ID: ExampleCo A former 97546 ExampleCo B pending 48541 ExampleCo A ready 75521 ExampleCo B former 50123 ExampleCo A contact 60047 ExampleCo B contact 19425 '; my @order; my $array={}; my @sparse; my @compact; for my $l (split("\n",$testout)) { chomp $l; my ($coid,$type,$state,$id)=split(' ',$l,4); next unless ($type eq 'A'); my $h={ID=>$id,CoID=>$coid,State=>$state}; push @order,$id; $array->{$id}=$h; $sparse[$id]=$h; push @compact,$h; } print 'From hash'."\n"; for my $o (@order) { my $h=$array->{$o}; print ' ID = '.$h->{ID}."\n"; print ' CoID = '.$h->{CoID}."\n"; print ' State = '.$h->{State}."\n"; } print 'iterate compact'."\n"; for my $h (@compact) { next unless (defined $h); print ' ID = '.$h->{ID}."\n"; print ' CoID = '.$h->{CoID}."\n"; print ' State = '.$h->{State}."\n"; } print 'index sparse'."\n"; for my $o (@order) { my $h=$sparse[$o]; print ' ID = '.$h->{ID}."\n"; print ' CoID = '.$h->{CoID}."\n"; print ' State = '.$h->{State}."\n"; }
    result
    From hash ID = 97546 CoID = ExampleCo State = former ID = 75521 CoID = ExampleCo State = ready ID = 60047 CoID = ExampleCo State = contact iterate compact ID = 97546 CoID = ExampleCo State = former ID = 75521 CoID = ExampleCo State = ready ID = 60047 CoID = ExampleCo State = contact index sparse ID = 97546 CoID = ExampleCo State = former ID = 75521 CoID = ExampleCo State = ready ID = 60047 CoID = ExampleCo State = contact
    This example does not need IPC::System::Simple to be preinstalled, uses the `$test` call format that you implied, captures only the type=a records, and shows it stored in a hash, compact array and sparse array, iterating over the compact array and indexing the sparse array.

    if you prefer to install IPC::System::Simple that is a much prettier program (edit:) and you add the test for type=a

      For your information, most (if not all) of your print statements can be interpolated. So this:

      print 'From hash'."\n"; for my $o (@order) { my $h=$array->{$o}; print ' ID = '.$h->{ID}."\n"; print ' CoID = '.$h->{CoID}."\n"; print ' State = '.$h->{State}."\n";

      Becomes this:

      print "From hash\n"; for my $o (@order) { my $h=$array->{$o}; print " ID = $h->{ID}\n"; print " CoID = $h->{CoID}\n"; print " State = $h->{State}\n";

      Or:

      print "From hash\n"; for my $o (@order) { print "" . " ID = $array->{$o}->{ID}\n" . " CoID = $array->{$o}{CoID}\n" . " State = $array->{$o}->{State}\n";

      Or with a heredoc, but I digress.

      Also, I'm curious as to why you're calling a hash $array... ;)

        What no example this time to prove it? I thought you always wanted to see examples

        I prefer to make it clear when a value comes from a variable rather than infer it does via interpolation. It also means it is clearer when i say

        my $thing='dog'; print 'many '.$thing.'s'."\n";
        rather than the more obscure
        my $thing='dog'; print "many ${thing}s\n";
        without getting caught by
        my $thing='dog'; print "many $things\n";
        Being clear is a good habit i started about 4 decades ago, after trying to read other peoples APL code. I mostly say my $n=scalar(@array); for clarity too.

        You are right about calling it $array, it started because eval142 said he wanted an indexed array of objects.

Re: Parsing output from a 'system' call into objects?
by stevieb (Canon) on Feb 21, 2017 at 19:56 UTC

    Very similar to anonymonk's post, but without the module (just got sidetracked before I could post the solution):

    use warnings; use strict; use Data::Dumper; my @lines = split /\n/, `cat data.txt`; my %out; for (@lines){ next if /CoID:/; my ($co, $type, $state, $id) = split; next if ! $id; next if $type ne 'A'; $out{$id}->{CoID} = $co; $out{$id}->{State} = $state; } print Dumper \%out;
      my @lines = split /\n/, `cat data.txt`;

      can be replaced by

      chomp( my @lines = `cat data.txt` );

      It only makes sense to commands different to cat , of course, otherwise you'd just

      open my $IN, '<', 'data.txt' or die $!; chomp( my @lines = <$IN> );

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      any comment on why you skipped the type eq 'A' requirement?

        Because I overlooked it. Added the single line to correct the oversight.

Re: Parsing output from a 'system' call into objects?
by Anonymous Monk on Feb 21, 2017 at 19:45 UTC
    use IPC::System::Simple 'capturex'; my @cmd = ('cat','fake.txt'); chomp( my @lines = capturex @cmd ); shift @lines; # header my %data; for (@lines) { my ($coid,$type,$state,$id) = split; $data{$id}{CoID} = $coid; $data{$id}{State} = $state; } use Data::Dump; dd \%data;
    Output
    { 19425 => { CoID => "ExampleCo", State => "contact" }, 48541 => { CoID => "ExampleCo", State => "pending" }, 50123 => { CoID => "ExampleCo", State => "former" }, 60047 => { CoID => "ExampleCo", State => "contact" }, 75521 => { CoID => "ExampleCo", State => "ready" }, 97546 => { CoID => "ExampleCo", State => "former" }, }
Re: Parsing output from a 'system' call into objects?
by NetWallah (Canon) on Feb 22, 2017 at 18:55 UTC
    I'm late to this party, as usual, but since the OP mentioned "Objects" - here is a working OO version:
    use strict; use warnings; BEGIN{ package Company; my (%by_id, %by_type); sub new{ my ($class,$coid,$type,$state,$id) = @_; my $self = bless {COID=>$coid,TYPE=>$type,STATE=>$state,ID=>$id}, + $class; $by_id{$id} = $self; push @{$by_type{$type}}, $self; return $self; } sub All_ID_callback{ # Class method my ($callback) = @_; for (sort keys %by_id){ $callback->($by_id{$_}, $_); } } sub get_id{ # CLASS method my ($id) = @_; return $by_id{$id}; } sub for_each_bytype_callback{ # CLASS method my ($type, $callback) = @_; for my $o (@{$by_type{$type}}){ $callback->($o); } } sub PRINT{ my ($self, $header) = @_; $header and print "$header\n"; print ' ID = ', $self->{ID}."\n"; print ' CoID = ', $self->{COID}."\n"; print ' State = ', $self->{STATE}."\n"; } } #--- Main ---- #my $testout=`$test list`; my $testout=' CoID: Type: State: ID: ExampleCo A former 97546 ExampleCo B pending 48541 ExampleCo A ready 75521 ExampleCo B former 50123 ExampleCo A contact 60047 ExampleCo B contact 19425 '; for my $l (split("\n",$testout)) { chomp $l; my $company = Company::->new(split(' ',$l,4)); } print "---In ID sequence---\n"; Company::All_ID_callback( ## In ID sequence sub{ my $o=shift; return unless $o->{TYPE} eq "A"; $o->PRINT(); }); print "---Selecting by type---\n"; Company::for_each_bytype_callback("A", sub{my $o=shift; $o->PRINT(); } );

            ...it is unhealthy to remain near things that are in the process of blowing up.     man page for WARP, by Larry Wall

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1182458]
Approved by herveus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (4)
As of 2024-04-16 05:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found