Perl reading configuration file without using Modules - perl

Let's say I have a configuration file.
Config.csv
Server,Properties
"so-al-1","48989"
"so-al-3","43278"
"so-al-5","12345"
I need to use a perl script to retrieve the server and properties from the file in order to use the varible's values in my script. Also our client server doesn't want us to install any modules.
So how do I read this document in variables without using a module?
open(FILE,"Config.csv");
undef($/); #sucks the entire file in at once
while(<FILE>){
(#words)=split(/\s+/);
}
close FILE;
for (#words){
s/[\,|\.|\!|\?|\:|\;]//g; #removed punctuation
$word{$_}++;
}
for (sort keys %word){
print "$_ occurred $word{$_} times\n";
}
I did try the above but it doesn't put it to a hash that I wanted.
Edited: I copied the code too fast and missed a line.
Edited: I just found out that there's a question like this in StackOverflow already. How can I parse quoted CSV in Perl with a regex?

Following the usual warning of "you should use a CSV module", this works:
#!/usr/bin/env perl
use warnings;
use strict;
my $header_str=<DATA>;
chomp $header_str;
my #header=$header_str =~ /(?:^|,)("(?:[^"]+|"")*"|[^,]*)/g;
my %fields;
my #temp;
my $line;
while($line=<DATA>){
chomp $line;
#temp = $line =~ /(?:^|,)("(?:[^"]+|"")*"|[^,]*)/g;
for (#temp) {
if (s/^"//) {
s/"$//; s/""/"/g;
}
}
$fields{$temp[0]}=$temp[1];
}
print "$_\t\t" for (#header);
print "\n";
print map { "$_\t\t$fields{$_}\n" } sort keys %fields;
__DATA__
Server,Properties
"so-al-1","48989"
"so-al-3","43278"
"so-al-5","12345"
Output:
Server Properties
so-al-1 48989
so-al-3 43278
so-al-5 12345

#!/usr/bin/perl
use warnings;
use strict;
while (<DATA>) {
chomp;
next unless my($key,$value) = split /,/;
s/^"//, s/"$// for $key, $value;
print "key=$key value=$value\n";
}
__DATA__
Server,Properties
"so-al-1","48989"
"so-al-3","43278"
"so-al-5","12345"

Related

How to write a correct name using combination of variable and string as a filehandler?

I want to make a tool to classify each line in input file to several files
but it seems have some problem in naming a filehandler so I can't go ahead , how do I solve?
here is my program
ARGV[0] is the input file
ARGV[1] is the number of classes
#!/usr/bin/perl
use POSIX;
use warnings;
# open input file
open(Raw,"<","./$ARGV[0]") or die "Can't open $ARGV[0] \n";
# create a directory class to store class files
system("mkdir","Class");
# create files for store class informations
for($i=1;$i<=$ARGV[1];$i++)
{
# it seems something wrong in here
open("Class$i",">","./Class/$i.class") or die "Can't create $i.class \n";
}
# read each line and random decide which class to store
while( eof(Raw) != 1)
{
$Line = readline(*Raw);
$Random_num = ceil(rand $ARGV[1]);
for($k=1;$k<=$ARGV[1];$k++)
{
if($Random_num == $k)
{
# Store to the file
print "Class$k" $Line;
last;
}
}
}
for($h=1;$h<=$ARGV[1];$h++)
{
close "Class$h";
}
close Raw;
thanks
Later I use the advice provided by Bill Ruppert
I put the name of filehandler into array , but it seems appear a syntax bug , but I can't correct it
I label the syntax bug with ######## A syntax error but it looks quite OK ########
here is my code
#!/usr/bin/perl
use POSIX;
use warnings;
use Data::Dumper;
# open input file
open(Raw,"<","./$ARGV[0]") or die "Can't open $ARGV[0] \n";
# create a directory class to store class files
system("mkdir","Class");
# put the name of hilehandler into array
for($i=0;$i<$ARGV[1];$i++)
{
push(#Name,("Class".$i));
}
# create files of classes
for($i=0;$i<=$#Name;$i++)
{
$I = ($i+1);
open($Name[$i],">","./Class/$I.class") or die "Can't create $I.class \n";
}
# read each line and random decide which class to store
while( eof(Raw) != 1)
{
$Line = readline(*Raw);
$Random_num = ceil(rand $ARGV[1]);
for($k=0;$k<=$#Name;$k++)
{
if($Random_num == ($k+1))
{
print $Name[$k] $Line; ######## A syntax error but it looks quite OK ########
last;
}
}
}
for($h=0;$h<=$#Name;$h++)
{
close $Name[$h];
}
close Raw;
thanks
To quote the Perl documentation on the print function:
If you're storing handles in an array or hash, or in general whenever you're using any expression more complex than a bareword handle or a plain, unsubscripted scalar variable to retrieve it, you will have to use a block returning the filehandle value instead, in which case the LIST may not be omitted:
print { $files[$i] } "stuff\n";
print { $OK ? STDOUT : STDERR } "stuff\n";
Thus, print $Name[$k] $Line; needs to be changed to print { $Name[$k] } $Line;.
How about this one:
#! /usr/bin/perl -w
use strict;
use POSIX;
my $input_file = shift;
my $file_count = shift;
my %hash;
open(INPUT, "<$input_file") || die "Can't open file $input_file";
while(my $line = <INPUT>) {
my $num = ceil(rand($file_count));
$hash{$num} .= $line
}
foreach my $i (1..$file_count) {
open(OUTPUT, ">$i.txt") || die "Can't open file $i.txt";
print OUTPUT $hash{$i};
close OUTPUT;
}
close INPUT;

perl file read, truncate

I am trying to modify a config file.
I first read it into #buffer, depending on a regex match.
The modified buffer gets written back on disk, in case the file got smaller, a trunciation is done.
Unfortunatly this does not work, and it already crashes at fseek, but as far as I can say my usage of fseek conforms to perl doc.
open (my $file, "+<", "somefilethatexists.txt");
flock ($file, LOCK_EX);
foreach my $line (<$file>) {
if ($line =~ m/(something)*/) {
push (#buffer, $line);
}
}
print "A\n";
seek($file,0,0); #seek to the beginning, we read some data already
print "B\n"; # never appears
write($file, join('\n',#buffer)); #write new data
truncate($file, tell($file)); #get rid of everything beyond the just written data
flock($file, LOCK_UN);
close ($file);
perlopentut says this about Mixing Reads and Writes
... when it comes to updating a file ... you probably don't want to
use this approach for updating.
You should use Tie::File for this. It opens the file for both read and write on the same filehandle and allows you to treat a file as an array of lines
use strict;
use warnings;
use Tie::File;
tie my #file, 'Tie::File', 'somefilethatexists.txt' or die $!;
for (my $i = 0; $i < #file; ) {
if (m/(something)*/) {
$i++;
}
else {
splice #file, $i, 1;
}
}
untie #file;
Where are your fseek(), fwrite() and ftruncate() functions defined? Perl doesn't have those functions. You should be using seek(), print() (or syswrite()) and truncate(). We can't really help you if you're using functions that we know nothing about.
You also don't need (and probably don't want) that explicit call to unlock the file or the call to close the file. The filehandle will be closed and unlocked as soon as your $file variable goes out of scope.
Maybe you can try this:
$^I = '.bak';
#ARGV = 'somefilethatexists.txt';
while (<>) {
if (/(something)*/) {
print;
}
}

Update the perl script to include number of times the row is repeated

I have below a perl script which gives a list of entries which are present more than once in a file/STDIN.
I want to update this script so that it also shows how many times the entries have been repeated.
#!/usr/bin/perl
use strict;
use warnings;
my %duplicates;
while (<>) {
chomp;
$duplicates{$_}++;
}
foreach my $key (keys %duplicates) {
if ($duplicates{$key} > 1) {
delete $duplicates{$key};
print "$key\n";
}
}
The delete builtin returns the value deleted. So you can use:
print "$key: ", delete $duplicates{$key}, "\n";
You can print $duplicates{$key} while iterating on keys:
#!/usr/bin/perl
use strict;
use warnings;
my %duplicates;
while (<>) {
chomp;
$duplicates{$_}++;
}
foreach my $key (keys %duplicates) {
if ($duplicates{$key} > 1) {
print "$key is repeated $duplicates{$key} times\n";
delete $duplicates{$key};
}
}
Just print $duplicates{$key}. Or am I missing something?
Also, are you sure you need to delete $duplicates{$key}?

help in parsing

I am having a XML file as shown below,
<message1>
<val1>100</val1>
<val2>200</val2>
<val3>300</val3>
<val4>400</val4>
</message1>
<message2>
<val1>100</val1>
<val2>200</val2>
<val3>300</val3>
<val4>400</val4>
</message2>
I have to parse the values (val) and i could not use XML::Simple module. The parsing should be started from <message1> and i have to put the values in an array till </message1> and then i have to repeat this for <message2> till </message2>.
Pictorially it is like
<message1>
----100
----200
----300
----400
</message1>
<message2>
----100
----200
----300
----400
</message2>
Can any one help me .. I am struggling a lot
Thanks
Senthil kumar
Since we're back in 1999, I think I would forget about strict and warnings, use symbolic references and string eval, and be done with it:
#!/usr/bin/perl
while( <DATA>)
{ s{<(message\d)>}{\#$1=(}; # #message1=(
s{<val\d>}{}; #
s{<\/val\d>}{,}; # ,
s{</message\d>}{);}; # );
$s.=$_;
};
eval $s;
$,= ", "; $\= "\n";
foreach (1..2) { print "\#message$_: ", #{"message$_"}; }
__DATA__
<message1>
<val1>100</val1>
<val2>200</val2>
<val3>300</val3>
<val4>400</val4>
</message1>
<message2>
<val1>100</val1>
<val2>200</val2>
<val3>300</val3>
<val4>400</val4>
</message2>
(in case that's not clear: that's a joke! As they say "Have you tried using an XML parser instead?")
Assuming your input is completely regular as you show, the following should work.
But you are far better off getting a real XML parser to work, by wrapping a root element around all your content or by parsing each message separately.
use strict;
use warnings;
my %data;
while (<>) {
# skip blank lines
next unless /\S/;
my ($tag) = /^<(.*)>$/
or warn("expected tag, got $_ "), next;
$data{$tag} ||= [];
while (<>) {
last if /^<\/\Q$tag\E>$/;
my (undef, $value) = /^<val(\d+)>(.*)<\/val\1>$/
or warn("expected val, got $_ "), next;
push #{ $data{$tag} }, $value;
}
}
use Data::Dumper;
print Dumper \%data;

What module can I use to parse RSS feeds in a Perl CGI script?

I am trying to find a RSS parser that can be used with a Perl CGI script. I found simplepie and that's really easy parser to use in PHP scripting. Unfortunately that doesn't work with a Perl CGI script. Please let me know if there is anything that's easy to use like simplepie.
I came across this one RssDisplay but I am not sure about the usage and also how good it is.
From CPAN: XML::RSS::Parser.
XML::RSS::Parser is a lightweight liberal parser of RSS feeds. This parser is "liberal" in that it does not demand compliance of a specific RSS version and will attempt to gracefully handle tags it does not expect or understand. The parser's only requirements is that the file is well-formed XML and remotely resembles RSS.
#!/usr/bin/perl
use strict; use warnings;
use XML::RSS::Parser;
use FileHandle;
my $parser = XML::RSS::Parser->new;
unless ( -e 'uploads.rdf' ) {
require LWP::Simple;
LWP::Simple::getstore(
'http://search.cpan.org/uploads.rdf',
'uploads.rdf',
);
}
my $fh = FileHandle->new('uploads.rdf');
my $feed = $parser->parse_file($fh);
print $feed->query('/channel/title')->text_content, "\n";
my $count = $feed->item_count;
print "# of Items: $count\n";
foreach my $i ( $feed->query('//item') ) {
print $i->query('title')->text_content, "\n";
}
Available Perl Modules
XML::RSS::Tools
XML::RSS::Parser:
#!/usr/bin/perl -w
use strict;
use XML::RSS::Parser;
use FileHandle;
my $p = XML::RSS::Parser->new;
my $fh = FileHandle->new('/path/to/some/rss/file');
my $feed = $p->parse_file($fh);
# output some values
my $feed_title = $feed->query('/channel/title');
print $feed_title->text_content;
my $count = $feed->item_count;
print " ($count)\n";
foreach my $i ( $feed->query('//item') ) {
my $node = $i->query('title');
print ' '.$node->text_content;
print "\n";
}
XML::RSS::Parser::Lite (Pure Perl):
use XML::RSS::Parser::Lite;
use LWP::Simple;
my $xml = get("http://url.to.rss");
my $rp = new XML::RSS::Parser::Lite;
$rp->parse($xml);
print join(' ', $rp->get('title'), $rp->get('url'), $rp->get('description')), "\n";
for (my $i = 0; $i < $rp->count(); $i++) {
my $it = $rp->get($i);
print join(' ', $it->get('title'), $it->get('url'), $it->get('description')), "\n";
}
dirtyRSS:
use dirtyRSS;
$tree = parse($in);
die("$tree\n") unless (ref $tree);
disptree($tree, 0);