I have a text file that shows a list of currency exchanges rates.
I have read the first line of the text file content and I need this line to be inserted into the input form.
Perl
#!/usr/local/bin/perl
use strict;
use warnings;
use CGI qw(:standard);
#use Data::Dumper;
#use CGI;
my $q = CGI->new;
my %data;
$data{name} = $q->param('name');
print header;
my $file = '/admin/currencyX.txt';
open my $info, $file or die "Could not open $file: $!";
while ( my $line = <$info> ) {
print $line, "<br>";
last if $. == 1;
}
print
start_html('A Simple Example'),
h1('A Simple Example'),
start_form,
"What's your value? <br>",
textfield(-name => 'name', -class => 'nm', -value => '$line'),
p,
submit(-value => 'Add', -name => 'ed'),
end_form,
hr;
if ( $ENV{'REQUEST_METHOD'} eq "POST" ) {
if ( $data{name} eq '' ) {
print "Please provide the input";
exit;
}
#print "response " . Dumper \%data;
}
if ( param() ) {
print
"Your name is",em(param('name')),
hr;
}
print end_html;
The text file has a similar values like
Text file
AFN Afghan Afghani 73.0556951371 0.0136881868
ALL Albanian Lek 108.3423252926 0.0092300031
DZD Algerian Dinar 117.9799583224 0.0084760159
AOA Angolan Kwanza 249.2606313396 0.0040118650
ARS Argentine Peso 28.2508833695 0.0353971232
AMD Armenian Dram 482.0941933740 0.0020742834
I need a correction to make this work.
textfield(-name => 'name', -class => 'nm', -value => '$line'),
Your problem appears to be that you have put $line in single quotes - which stops it being interpolated. Try just removing them.
textfield(-name => 'name', -class => 'nm', -value => $line),
The best way to do this is to find an alternative to out putting the text value
open my $getV, '<', "/admin/currencyX.txt";
my $realV = <$getV>;
close $getV;
print $realV; # will out put AFN Afghan Afghani 73.0556951371 0.0136881868
Then append the string to a html input value
"What's your value? <br>",textfield(-name =>'name', -class =>'nm', -value =>$realV),
Related
I am new in perl struggling to build my 1st script but, the partition module doesn't work. More details are commented in the code. Maybe the code should be rewritten using hash and reference but I have no idea how to do it. Can someone please, help me?
#!/usr/bin/perl -w
#This script compares the today's result and yesterday's results between partitions for each host.
#The "df" output is stored in a CSV file. If any partitions have been changed (mounted/unmounted)
#the script must to warn and don't compare the results for that host.
use warnings;
my $file = "/tmp/df.csv";
my $host = `hostname | awk -F'.' '{print \$1}'`;
my $yesterdays_date = `date -d "-1 day" '+%d.%m.%Y'`;
my $todays_date = `date '+%d.%m.%Y'`;
chomp ($host, $yesterdays_date, $todays_date);
open(HANDLE, "$file") or die "Error opening file $file: $!";
my #array = <HANDLE>;
foreach (#array){
#columns = split /,/;
if(/$host/ and /$todays_date/){
my $todays_result = $columns[5];chomp;
#my $todays_partition = $columns[6];chomp;
print "Today\'s disk usage on $host: $columns[5]\n";
#print "$todays_result <<T.Result T.Partition>> $todays_partition"
}
elsif(/$host/ and /$yesterdays_date/){
my $yesterdays_result = $columns[5];chomp;
#my $yesterdays_partition = $columns[6];chomp;
print "Yesterday\'s disk usage on $host: $columns[5]\n";
#print "$yesterdays_result <<Y.Result Y.Partition>> $yesterdays_partition";
}
#Debug: Print differences in mount point (condition must be "ne" instead eq)
#if ($todays_partition eq $yesterdays_partition){
#print "$todays_partition <<Partition equal>> $yesterdays_partition";
#}
#else{
#print "Debug: Host or Date DIFFERENT or NOT FOUND for today and yesterday\n";
#}
#TO DO: print "The diference: $todays_result-$yesterdays_result", "\n";
};
close HANDLE;
The CSV file contains the following lines:
testhost,25.08.2018,100M,0,100M,0,/run/user/0
localhost,01.09.2018,6.7G,1.5G,5.2G,23,/
localhost,01.09.2018,485M,0,485M,0,/dev
localhost,01.09.2018,496M,4.0K,496M,1,/dev/shm
localhost,01.09.2018,496M,6.7M,490M,2,/run
localhost,01.09.2018,496M,0,496M,0,/sys/fs/cgroup
localhost,01.09.2018,497M,110M,387M,23,/boot
localhost,01.09.2018,100M,0,100M,0,/run/user/0
localhost,02.09.2018,6.7G,1.5G,5.2G,23,/
localhost,02.09.2018,485M,0,485M,0,/dev
localhost,02.09.2018,496M,4.0K,496M,1,/dev/shm
localhost,02.09.2018,496M,6.7M,490M,2,/run
localhost,02.09.2018,496M,0,496M,0,/sys/fs/cgroup
localhost,02.09.2018,497M,110M,387M,23,/boot
localhost,02.09.2018,100M,0,100M,0,/run/user/0
Bonus: Help with English grammar :D
You need information from multiple lines, so you will need some variables outside of the loop.
If the records in the CSV are ordered chronologically, you can use the following:
use strict;
use warnings;
use DateTime qw( );
use Sys::Hostname qw( hostname );
use Text::CSV_XS qw( );
my $qfn = "/tmp/df.csv";
open(my $fh, '<', $qfn)
or die("Can't open \"$qfn\": $!\n");
my $target_host = hostname =~ s/\..*//rs; # /
my $today_dt = DateTime->now( time_zone => "local" )->set_time_zone("floating")->truncate( to => "day" );
my $yday_dt = $today_dt->clone->subtract( days => 1 );
my $today = $today_dt->strftime("%d.%m.%Y");
my $yday = $yday_dt ->strftime("%d.%m.%Y");
my $csv = Text::CSV_XS->new({ auto_diag => 2, binary => 1 });
my %yday_usage_by_partition;
while ( my $row = $csv->getline($fh) ) {
my ($host, $date, $partition, $usage) = #$row[0,1,6,5];
next if $host ne $target_host;
if ($date eq $yday) {
$yday_usage_by_partition{$partition} = $usage;
}
elsif ($date eq $today) {
if (!exists($yday_usage_by_partition{$partition})) {
warn("No data for $yday for partition $partition\n");
next;
}
print("$partition: $$yday_usage_by_partition{$partition} -> $usage\n");
}
}
currently I have the following script
#!/usr/bin/env perl
use strict;
use warnings;
my %seen;
my $header = <> . <>;
print $header;
my $last_sequence_number = 0;
open( my $output, ">", "output.$last_sequence_number.out" ) or die $!;
print {$output} $header;
$seen{$last_sequence_number}++;
while (<>) {
my ($key) = split;
next unless $key =~ m/^\d+$/;
my $sequence_number = int( $key / 1000 );
if ( not $sequence_number == $last_sequence_number ) {
print "Opening new file for $sequence_number\n";
close($output);
open( $output, ">", "output.$sequence_number.out" ) or die $!;
print {$output} $header unless $seen{$sequence_number}++;
$last_sequence_number = $sequence_number;
}
print {$output} $_;
}
the script splits a file into other files with the pattern file 1 file 2 ... now I would need to pass to the script another parameter which allows to specify a prefix for the output so if this additional input is 1 then the output would be
1_file1,1_file2....and so on.. how could I do that?
I know that something like
use Getopt::Long;
could be used?
tried this
#!/usr/bin/env perl
use strict;
use warnings;
my %seen;
my $header = <> . <>;
print $header;
my ( $suffix, $filename ) = #ARGV;
open ( my $input, "<", $filename ) or die $!;
my $last_sequence_number = 0;
open( my $output, ">", "output.$last_sequence_number.out" ) or die $!;
print {$output} $header;
$seen{$last_sequence_number}++;
while (<$input>) {
my ($key) = split;
next unless $key =~ m/^\d+$/;
my $sequence_number = int( $key / 1000 );
if ( not $sequence_number == $last_sequence_number ) {
print "Opening new file for $sequence_number\n";
close($output);
open( $output, ">", "output.$sequence_number.out" ) or die $!;
print {$output} $header unless $seen{$sequence_number}++;
$last_sequence_number = $sequence_number;
}
print {$output} $_;
}
but that is not working. What is wrong?
I get
No such file or directory at ./spl.pl line 10, <> line 2.
after the header is printed.
As Sobrique says, your problem is the magical nature of <>. But I don't think that it's as hard to deal with as he thinks.
The point is that <> looks at the current value of #ARGV. So you can add other command line arguments as long as you ensure that you have removed them from #ARGV before you use <> for the first time.
So change your code so that it starts like this:
my %seen;
my $prefix = shift;
my $header = <> . <>;
You can then call your program like this:
$ your_program.pl prefix_goes_here list of file names...
Everything else should now work the same as it currently does, but you have your prefix stored away in $prefix so that you can use it in your print statements.
I hope that's what you wanted. Your question isn't particularly clear.
I would do something like this.
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Getopt::Long qw(:config bundling);
use Pod::Usage;
{
my $man = 0;
my $help = 0;
my $verbose = 0;
my $prefix = '';
my $suffix = '';
my $header_lines = 2;
my $bunch_size = 1000;
GetOptions(
'help|?' => \$help,
'man' => \$man,
'verbose|v+' => \$verbose,
'prefix|p=s' => \$prefix,
'suffix|s=s' => \$suffix,
'header|h=i' => \$header_lines,
'bunch|batch|bucket|b=i' => \$bunch_size
) or pod2usage(2);
pod2usage(1) if $help;
pod2usage( -exitval => 0, -verbose => 2 ) if $man;
pod2usage(
-exitval => 3,
-message => "Headers lines can't be negative number"
) if $header_lines < 0;
pod2usage(
-exitval => 4,
-message => "Bunch size has to be positive"
) unless $bunch_size > 0;
my $header = '';
$header .= <> for 1 .. $header_lines;
my %seen;
my $current_output_number = -1;
sub key2output { int( shift() / $bunch_size ) }
sub set_output {
my $output_number = shift;
if ( $output_number != $current_output_number ) {
my $seen = $seen{$output_number}++;
printf STDOUT "Opening %sfile for %d\n", $seen ? '' : 'new ',
$output_number
if $verbose;
open my $fh, $seen ? '>>' : '>',
$prefix . $output_number . $suffix;
select $fh;
print $header unless $seen;
$current_output_number = $output_number;
}
}
}
while (<>) {
my ($key) = /^(\d+)\s/;
next unless defined $key;
set_output( key2output($key) );
print;
}
__END__
=head1 NAME
code.pl - splits file by first number by thousands
=head1 SYNOPSIS
code.pl [options] [file ...]
Options:
--help brief help message
--man full documentation
--prefix output filename prefix
--suffix outpit filename suffix
--header number of header lines (default: 2)
=head1 OPTIONS
=over 8
=item B<--help>
Print a brief help message and exits.
=item B<--man>
Prints the manual page and exits.
=back
=head1 DESCRIPTION
B<This program> will read the given input file(s) and do something
useful with the contents thereof.
=cut
Just finish documentation and you can ship it to your colleagues.
The problem you've got is that the diamond operator <> is a piece of special perl magic.
It takes 'all filenames on command line' opens them and processes them in order.
To do what you're trying to do:
my ( $suffix, $filename ) = #ARGV;
open ( my $input, "<", $filename ) or die $!;
Then you can change your while loop to:
while ( <$input> ) {
And modify the output filename according to your desires. The key different there is that it'll only take one filename at that point - first arg is suffix, second is name.
You could perhaps extend this with:
my ( $suffix, #names ) = #ARGV;
And then run a foreach loop:
foreach my $filename ( #names ) {
open .... #etc
I have a certain script , which will segregate the log file and put the result.txt which is comming as expected. But i want to sent mail after this segregate log file attach it in the text file and sent. There is no error in this script but i need to enhance it. Please help me on how i can use it
#use Win32;
if (#ARGV != 2) {
print "Please pass atleast one paramer\n";
print "Usage:\n\t $0 <file_name><Pattern>\n";
exit;
}
$File_name = $ARGV[0];
$res_File_name = $File_name . "\.result\.txt";
$Pattern = $ARGV[1];
chomp($Pattern);
open(FD,"$File_name") or die ("File '$File_name' could not be open \n");
open(WFD,">$res_File_name") or die("File $res_File_name could not be opened\n");
print "Enter begin match pattern: ";
$bgn = <stdin>;
chomp($bgn);
print $bgn;
print "Enter end match pattern: ";
$en = <stdin>;
chomp($en);
while ($line = <FD>) {
chomp($line);
if ($line =~ /^$bgn/) { #seaching a patter at begining of the string.
print WFD "Begin pattern '$bgn' matched with the line '$line'\n";
}
if ($line =~ /$en$/) { #seaching a patter at end of the string.
print WFD "End pattern '$en' matched with the line '$line'\n";
#exit;
}
print WFD $_ if(/$Pattern/);
# main();
# use constant Service_Name =>'MyServ'
# use constant Service_Desc =>'MyServDesc'
# sub main()
# {
# $opt=shift(# ARGV)||""
# if ($opt =~ /^(-i|--install)$/i)
# {
install _service( Service_Name, Service_Desc)
# }
# elsif ($opt =~ /^(-r|--remove)$/i)
# {
# remove_service(Service_Name);
# }
# elsif ($opt =~ /^(run)$/i)
#}
# here we create a log file wth STDOUT and STDERR
# The log file will be created with extension .log
$log = $cwd . $bn . ".log";
# open(STDOUT, ">> $log") or die "Couldn't open $log for appending: $!\n";
# open(STDERR, ">&STDOUT") or die "Could";
close(FD);
close(WFD);
The standard way to create and send email using Perl is to use the many modules in the Email::* namespace.
For creating simple email, you should use Email::Simple.
use Email::Simple;
my $email = Email::Simple->create(
header => [
From => 'casey#geeknest.com',
To => 'drain#example.com',
Subject => 'Message in a bottle',
],
body => '...',
);
$email->header_set( 'X-Content-Container' => 'bottle/glass' );
For more complex email (i.e. ones with multiple parts, like file attachments or HTML versions) use Email::MIME.
To send an email, use Email::Sender (actually, in most cases, you can probably get away with Email::Sender::Simple)
use Email::Sender::Simple qw(sendmail);
sendmail($email); # The $email we created in the previous example.
Your first "enhancement" should be to add use strict and use warnings to the top of your program, and declare all your variables using my. That should be your first thought when writing any Perl program.
As for sending an email, you don't say what it is you want to send, but I suggest you use the MIME::Lite module.
I am trying to read the output of webservice and write to a csv file. The source has many fields and it is quoted with comma delimiter.
A few columns have values on a new line too.
213,"Dan","This is kool","dblee"
214,"Taylot","This is,
not mine","typelee"
Output
213,"Dan","dblee"
214,"Taylot","typelee"
Here I am trying to use get to capture of the output of WS. But facing a problem while trying to read individual fields.This ($csv->getline($fh1)) is not returning an array.
How to make it to return an array. Any inputs.
use Getopt::Long;
use File::Copy;
use Text::CSV;
my $filename = '/mydir/file.txt';
my $filename2 = '/mydir/file_formatted.csv';
unlink $filename;
for ( my $i = 1 ; $i <= 2 ; $i++ )
{
$WS_URL = "https://adesfhr.com/wpi.php?cmd=dsd&PageNumber=$i&pageSize=10&responseType=csv"; `
my $resp = $SSO->get($WS_URL); `
my $data = $resp->content(); `
last if ! $data; `
if ($data) {
my $csv = Text::CSV->new(
{
binary => 1, # Allow special character. Always set this
auto_diag => 1, # Report irregularities immediately
sep_char => ',', #Separatrp
}
);
open( my $fh1, "<:encoding(utf8)", \$data ) or die "$!";
open( my $fh2, '>>', $filename )
or die "Could not open file '$filename' $!";
<$fh1>;
while ( my $row = $csv->getline($fh1) ) {
my $newrow = splice( #$row, 0, 3 );
print "#$newrow\n";
$csv->print( $fh2, $newrow );
}
close $fh2;
close $fh1;
}
}
.CS contains string within double quotes and I am trying to extract these strings into .resx file.
The existing code output the .resx but with only one string whereas .CS file contains more than one strings in quotes.
Can you please provide any reference to achieve this?
use strict;
use warnings;
use File::Find;
use XML::Writer;
use Cwd;
#user input: [Directory]
my $wrkdir = getcwd;
system "attrib -r /s";
print "Processing $wrkdir\n";
find( \&recurse_src_path, $wrkdir );
sub recurse_src_path
{
my $file = $File::Find::name;
my $fname = $_;
my #lines;
my $line;
if ( ( -f $file ) && ( $file =~ /.*\.cs$/i ) )
{
print "..";
open( FILE, $file ) || die "Cannot open $file:\n$!";
while ( $line = <FILE> )
{
if ( $line =~ s/\"(.*?)\"/$1/m )
{
chomp $line;
push( #lines, $line );
my $nl = '0';
my $dataIndent;
my $output = new IO::File(">Test.resx");
#binmode( $output, ":encoding(utf-8)" );
my $writer = XML::Writer->new(
OUTPUT => $output,
DATA_MODE => 1,
DATA_INDENT => 2
);
$writer->xmlDecl("utf-8");
$writer->startTag('root');
foreach my $r ($line)
{
print "$1\n";
$writer->startTag( 'data', name => $_ );
$writer->startTag('value');
$writer->characters($1);
$writer->endTag('value');
$writer->startTag('comment');
$writer->characters($1);
$writer->endTag('comment');
$writer->endTag('data');
}
$writer->endTag('root');
$writer->end;
$output->close();
}
}
close FILE;
}
}
Use the /g regex modifier. For example:
use strict;
use warnings;
my $cs_string = '
// Imagine this is .cs code here
system "attrib -r /s";
print "Processing $wrkdir\n";
find( \&recurse_src_path, $wrkdir );
';
while ($cs_string =~ /\"(.*)\"/g) {
print "Found quoted string: '$1'\n"
}
;
See also: http://perldoc.perl.org/perlrequick.html#Matching-repetitions
You might also want to look at File-Slurp to read your .cs code into a single Perl scalar, trusting that your .cs file is not too large.
Finally combine this with your existing code to get the .resx output format.