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

Hi Monks, some time ago I posted my problem about having a wrapper script for starting services in linux. I now have the following hashes.
our %services = ( 1 => { name => "service1", host => { host1 => 1 }, }, 2 => { name => "service2", host => { host0 => 2, host5 => 2 }, }, ); print "----------------Menu-----------------------------------------\n +"; print "Please enter the number of the service and press return\n"; print "-------------------------------------------------------------\n +"; for $row (sort keys %services){ my $service=$services{$row}; print "$row\t $service->{ name }\n"; } print "Please enter number -->";
I don't want to really be adding new hashes to the program in the future to add new services. I think it would be a lot neater to read it from a file. Is it possible to put the hash information in a flat text file, so I can read the contents from the text file and create new hashes with service information? I read something about a tie option in Perl for connecting to text file databases, but I don't know how I would read it in and put into hashes. Any help, or pointer in the right direction would be appreciated. Thanks.
  • Comment on Reading from a flat text file database and storing contents in a hash
  • Download Code

Replies are listed 'Best First'.
Re: Reading from a flat text file database and storing contents in a hash
by GrandFather (Saint) on Apr 20, 2007 at 11:47 UTC

    There are many different ways you could tackle this depending in large part how the configuration/data base file will be maintained. If you are writing a separate application to manage the file then you could use XML::Simple, Data::Dump::Streamer, a real data base using DBI and DBD::SQLite or a whole range of other options.

    If your file format is XML or YAML there is a chance that it could be edited manually without breaking things, with YAML likely to be easier to get on with than XML.

    Alternatively you could choose one of the plethora of configuration file formats (often Windows .ini style) and pick a module from CPAN to load it for you (there are many).

    Or lastly, you could roll your own application specific file format and parse that. Code to do that using Perl is likely to be pretty small if you are even halfway smart about your file format and field separators.

    The key question though is: hand edited or managed. Keep in mind that if you allow it to be hand edited, one day someone is going to screw it up.


    DWIM is Perl's answer to Gödel
      Thanks for your help guys. In giving more thought to the problem, what I want to do is not hand edit the flat text file, but rather build an admin menu, so I can enter new services when needed. Also I wanted to get rid of the hash at the beginning of my program, which has the services in it and having to update it by hand. Instead I wanted to populate the hash with whatever is in the flat text file Does anybody know how I can do this?

        If the number of entries (for whatever definition of entry) is modest then using Data::Dump::Streamer is likely to be as good as anything. If you anticipate a large number of entries then it's probably worth finding out about DBI and the various DBD drivers that allow you to use a "real" data base.

        However, for the simple case consider:

        use strict; use warnings; use Data::Dump::Streamer; my %services = ( 1 => { name => "service1", host => { host1 => 1 }, }, 2 => { name => "service2", host => { host0 => 2, host5 => 2 }, }, ); Dump (\%services); open TEMP, '>', 'temp.txt'; print TEMP Dump (\%services)->Out (); close TEMP; my $newServices = do 'temp.txt'; Dump ($newServices);

        Prints:

        $HASH1 = { 1 => { host => { host1 => 1 }, name => 'service1' }, 2 => { host => { host0 => 2, host5 => 2 }, name => 'service2' } }; $HASH1 = { 1 => { host => { host1 => 1 }, name => 'service1' }, 2 => { host => { host0 => 2, host5 => 2 }, name => 'service2' } };

        DWIM is Perl's answer to Gödel
        I've just looked into XML::Simple as suggested and I can see how I can achieve what I wanted the program to do. Thanks guys.
Re: Reading from a flat text file database and storing contents in a hash
by wfsp (Abbot) on Apr 20, 2007 at 11:40 UTC
    You can use Data::Dumper to do that.
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; $Data::Dumper::Indent = 1; my %services = ( 1 => { name => "service1", host => { host1 => 1 }, }, 2 => { name => "dxuldm", host => { host0 => 2, host5 => 2 }, }, ); open my $fh, '>', 'services.txt' or die "can't open to write: $!\n"; print $fh Data::Dumper->Dump([\%services], [qw(services_restored)]); close $fh; our $services_restored; eval {do 'services.txt'}; print Dumper $services_restored;
    output:
    $VAR1 = { '1' => { 'name' => 'service1', 'host' => { 'host1' => 1 } }, '2' => { 'name' => 'dxuldm', 'host' => { 'host0' => 2, 'host5' => 2 } } };
Re: Reading from a flat text file database and storing contents in a hash
by dragonchild (Archbishop) on Apr 20, 2007 at 13:32 UTC
    Use DBM::Deep. Then, provide a simple script to add a service. In fact, this kind of service manager begs for a master script that you launch to add, remove, start, stop, and list the services.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      This is all really good advice, but at the moment I have been playing around with XML::Simple. The problem that I am having is I cannot generate the data structure that I had before with the hash it keeps on putting things in a nested array. This is what I used to have before using XML::Simple
      $VAR1 = '1'; $VAR2 = { 'host' => { 'hosta' => 1 }, 'name' => 'servicea' }; $VAR3 = '2'; $VAR4 = { 'host' => { 'host0' => 2, 'host5' => 2 }, 'name' => 'serviceb' };
      When using XML::Simple I get this:
      $VAR1 = { 'name' => 'servicea', 'host' => [ { 'hosta' => '2' }, { 'hostb' => '2' } ]
      I am using the following XML with XML::simple.
      <?xml version='1.0'?> <services> <name>servicea</name> <host> <hosta>2</hosta> </host> <host> <hosta>2</hosta> </host> </services>
      Is there any way I can change the XML, so XML::simple only uses hash of hashes instead of hashes and arrays? Thanks
        *sighs* I provide you with a suggestion. You say "That's cool, but can you debug what's wrong with this other mechanism?" XML is a very poor solution for this, which is why I suggested DBM::Deep. dbm-deep is designed to solve this specific problem that you're working with - easy persistence of Perl datastructures.

        Use the proper solution for the job. XML isn't it.


        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?