open command in perl - linux

I am try to use open command in perl. But getting and error as follows.
Command
open(IN_TRIALS, '<', "F:/2010_nist_sre_test_set/data/eval/keys/coreext-coreext.trialkey.csv") or die "cannot open trials list";
Error
cannot open trials.
how to fix this?

First, make sure the file exists in the location: F:/2010_nist_sre_test_set/data/eval/keys/coreext-coreext.trialkey.csv.
Use a modern way to read a file, using a lexical filehandle:
#!/usr/bin/perl
use strict;
use warnings;
my $filename = "F:/2010_nist_sre_test_set/data/eval/keys/coreext-coreext.trialkey.csv";
open(my $fh, '<:encoding(UTF-8)', $filename)
or die "Could not open file '$filename' $!";
...
...
close $fh;
If you're reading a csv file then it is recommended to use Perl Module Text::CSV_XS.
If you use Text::CSV_XS, here is the syntax:
use Text::CSV_XS;
my $csv = Text::CSV_XS->new ({ binary => 1, auto_diag => 1 });
my $filename = "F:/2010_nist_sre_test_set/data/eval/keys/coreext-coreext.trialkey.csv";
open my $fh, "<:encoding(utf8)", $filename or die "$filename: $!";
while (my $row = $csv->getline ($fh)) {
#do the necessary operation
}
close $fh;

Related

Perl Net::FTP get error Bad remote filename 'ex.pl

I have file called ftp which has filename e.g ex.pl as its only content and am i trying to read it via file handle and store it in scalar variable and trying to get it through $ftp->get but it gives error: Bad remote filename 'ex.pl
'
where ex.pl is an actual file stored in my directory.
Here is my code:
sub restore () {
#open (IN,"ftpfile") or die "failed to open: $!";
open( INN, "ftp" ) or die "fail to open: $!";
my $array = <INN>;
print $array;
my $ftp = Net::FTP->new("$ARGV[0]") or die "host error: $#";
$ftp->login( "$ARGV[1]", "$ARGV[2]" )
or die "login error: ", $ftp->message;
$ftp->cwd("/home/qwerty/perl");
$ftp->get("$array") or die "error:", $ftp->message;
}
restore;
The problem here is - you need to chomp $array; because otherwise you get a newline embedded.
I would note - you're doing something a little messy with that open call - INN will be a global file handle, and you don't close it. It would be better to:
open ( my $input, "<", "ftp" ) or die $!;
my $filename = <$input>; #read one line;
chomp $filename;
I would also suggest assigning name/login etc. earlier on in your program:
my ( $hostname, $login, $password ) = #ARGV;
Because then you can error check these things (e.g. if they exist, and are valid etc.).

Trying to read a pdf, parse the data, and write desired data to spreadsheet using Perl on Linux

I am trying to extract data from credit card statements and enter it into a spreadsheet for tax purposes. What I've done so far involves multiple steps but I'm relatively new to Perl and am working from what I know. Here are two separate scripts I've written so far...one reads all data from a pdf and writes to a text file, the other parses the text (imperfectly) and writes it to another text file. Then I'd like to either create a csv file to import into a spreadsheet or write directly to a spreadsheet. I'd like to do this in one script but two or three will suffice.
first script:
#!/usr/bin/perl
use CAM::PDF;
my $file = "/home/cd/Documents/Jan14.pdf";
my $pdf = CAM::PDF->new($file);
my $doc="";
my $filename = 'report.txt';
open(my $fh, '>', $filename) or die "Could not open file '$filename' $!";
for ($i=1; $i <= $pdf->numPages(); $i++) {
$doc = $doc.$pdf->getPageText($i);
}
print $fh " $doc\n";
close $fh;
print "done\n";
Second script:
#!/usr/bin/perl
use strict;
use warnings;
undef $/; # Enable 'slurp' mode
open (FILE, '<', 'report.txt') or die "Could not open report.txt: $!";
my $file = <FILE>; # Whole file here now...
my ($stuff_that_interests_me) =
($file =~ m/.*?(Date of Transaction.*?CONTINUED).*/s);
print "$stuff_that_interests_me\n";
my $filename = 'data.txt';
open(my $fh, '>>', $filename) or die "Could not open file '$filename' $!";
print $fh " $stuff_that_interests_me\n";
close $fh;
print "done\n";
close (FILE) or die "Could not close report.txt: $!";
open (FILE2, '<', 'report.txt') or die "Could not open report.txt: $!";
my $file2 = <FILE2>; # Whole file here now...
my ($other_stuff_that_interests_me) =
($file2 =~ m/.*?(Page 2 .*?TRANSACTIONS THIS CYCLE).*/s);
print "$other_stuff_that_interests_me\n";
$filename = 'data.txt';
open($fh, '>>', $filename) or die "Could not open file '$filename' $!";
print $fh " $other_stuff_that_interests_me\n";
close $fh;
print "done\n";
close (FILE2) or die "Could not close report.txt: $!";
Update:
I found a module (CAM:PDF) on CPAN that works great for what I'm trying to do...it even renders the data in a format that I can more easily use for my spreadsheet. However, I haven't yet figured out how to get it to print to a .txt file...any suggestions?
#!/usr/bin/perl -w
package main;
use warnings;
use strict;
use CAM::PDF;
use Getopt::Long;
use Pod::Usage;
use English qw(-no_match_vars);
our $VERSION = '1.60';
my %opts = (
density => undef,
xdensity => undef,
ydensity => undef,
check => 0,
renderer => 'CAM::PDF::Renderer::Dump',
verbose => 0,
help => 0,
version => 0,
);
Getopt::Long::Configure('bundling');
GetOptions('r|renderer=s' => \$opts{renderer},
'd|density=f' => \$opts{density},
'x|xdensity=f' => \$opts{xdensity},
'y|ydensity=f' => \$opts{ydensity},
'c|check' => \$opts{check},
'v|verbose' => \$opts{verbose},
'h|help' => \$opts{help},
'V|version' => \$opts{version},
) or pod2usage(1);
if ($opts{help})
{
pod2usage(-exitstatus => 0, -verbose => 2);
}
if ($opts{version})
{
print "CAM::PDF v$CAM::PDF::VERSION\n";
exit 0;
}
if (defined $opts{density})
{
$opts{xdensity} = $opts{ydensity} = $opts{density};
}
if (defined $opts{xdensity} || defined $opts{ydensity})
{
if (!eval "require $opts{renderer}") ## no critic (StringyEval)
{
die $EVAL_ERROR;
}
if (defined $opts{xdensity})
{
no strict 'refs'; ## no critic(ProhibitNoStrict)
my $varname = $opts{renderer}.'::xdensity';
${$varname} = $opts{xdensity};
}
if (defined $opts{ydensity})
{
no strict 'refs'; ## no critic(ProhibitNoStrict)
my $varname = $opts{renderer}.'::ydensity';
${$varname} = $opts{ydensity};
}
}
if (#ARGV < 1)
{
pod2usage(1);
}
my $file = shift;
my $pagelist = shift;
my $doc = CAM::PDF->new($file) || die "$CAM::PDF::errstr\n";
foreach my $p ($doc->rangeToArray(1, $doc->numPages(), $pagelist))
{
my $tree = $doc->getPageContentTree($p, $opts{verbose});
if ($opts{check})
{
print "Checking page $p\n";
if (!$tree->validate())
{
print " Failed\n";
}
}
$tree->render($opts{renderer});
}
I'd like to either create a csv file to import into a spreadsheet or
write directly to a spreadsheet.
You can write directly to the spreadsheet, check out Excel::Writer::XLSX.
If you want to create a CSV file then you can try using Text::CSV and Text::CSV_XS.

Perl - Dropping delimited text files into one Excel file with tabs

Returning to Perl after some time off, I have been looking for a way to drop some tab delimited text files into an array and then into an Excel file; basically an Excel tab generated for each text file in a directory. Generally the text files are a similar format.
The code below which has been cobbled from examples generally produces what I am after. However the output ignores any tabs and prints all text (per row) in one string. I am struggling with how to implement the tab delimiter into the code. I know I will need to split the text files as they are pushed into the array. I had been playing around with hashes, but I think I am looking too far into the problem, and it's likely to be an obvious answer that I am missing.
use warnings;
use strict;
use Cwd qw(abs_path);
use Spreadsheet::WriteExcel;
die "Log path ARG required " unless defined $ARGV[0];
my $path = abs_path( $ARGV[0] );
my $workbook = Spreadsheet::WriteExcel->new("resultsbook.xls");
chdir $path or die "no such directory: $!";
if ( -d $path ) { ## test if $path given is a directory
opendir my $dir, $path or die "can't open the directory: $!";
while ( defined( my $file = readdir($dir) ) ) {
chomp $file;
next if $file eq '.' or $file eq '..';
(my $sheetname = $file) =~s/\.\w+?//;
my $wrksheet = $workbook->add_worksheet($sheetname);
$wrksheet->write_col( 0, 0, [ #{ readfile($file) } ] );
}
}
sub readfile {
my $textfilecontent = [];
open my $fh, '<', shift() or die "can't open file:$!";
while (<$fh>) {
chomp;
push #{$textfilecontent}, $_, $/;
}
return $textfilecontent;
}
You need to split the lines with tab (or whatever delimiter) before pushing them into the #textfilecontent variable. There are a couple of other minor corrections in here:
use warnings;
use strict;
use Cwd qw(abs_path);
use Spreadsheet::WriteExcel;
die "Log path ARG required " unless defined $ARGV[0];
my $path = abs_path( $ARGV[0] );
my $workbook = Spreadsheet::WriteExcel->new("resultsbook.xls");
chdir $path or die "no such directory: $!";
if ( -d $path ) { ## test if $path given is a directory
opendir my $dir, $path or die "can't open the directory: $!";
while ( defined( my $file = readdir($dir) ) ) {
chomp $file;
next if $file eq '.' or $file eq '..';
(my $sheetname = $file) =~s/\.\w+//;
my $wrksheet = $workbook->add_worksheet($sheetname);
$wrksheet->write_col( 0, 0, readfile($file));
}
}
sub readfile {
my #textfilecontent = ();
open my $fh, '<', shift() or die "can't open file:$!";
while (<$fh>) {
chomp;
push #textfilecontent, [split(/\t/)];
}
return \#textfilecontent;
}

how to dump output of a perl script on linux into a log file with file name as timestamp

I have a perl script example.pl that I run on linux box. I need to capture the output from the execution of the perl script and timestamp its name. I know the output redirection method but I am looking for a way to do it from the script example.pl itself (if possible)
It's easy to redirect the STDOUT to a file. Just do this at the beginning of the script:
open STDOUT, '>', "my_stdout_file.txt";
And this is a function that returns a file name with a timestamp:
sub generate_timestamp_filename {
my $tstamp = sprintf( "%04d%02d%02d%02d%02d%02d",
$now[5]+1900,
$now[4]+1,
$now[3],
$now[2],
$now[1],
$now[0] );
return "my_prefix_$tstamp.txt";
}
You can redirect output and error streams using Typeglobs or you can do the following.
#!/bin/perl
open(STDOUT, '>',time.".out") or die $!; #the time function gives you the timestamp
open(STDERR, '>',time.".err") or die $!;
print "output"; #goes to <timestamp>.out
warn "error"; #goes to <timestamp>.err
Here is the quickest way to do this:
open(STDOUT, ">myfile") or die $!;
print "Hello world"; #now goes to myfile
open(STDERR, ">hisfile") or die $!;
warn "Error here"; #and that's in hisfile
The other alternative is to use select:
open(my $FILE, ">stdout") or die $!;
my $old = select($FILE);
# Done capturing output
select $old;

copying data from multiple files and adding to different files

okay, i am not sure whether this is even possible or not..I may sound stochastic...
There are around 250 files with names as
Eg:1
1_0.pdb,1_60.pdb,1_240.pdb,....50_0.pdb,50_60.pdb,50_240.pdb..... having some data.
Now for each of the above file there is a another file of same name....just prefix file is added...Like:
E.g:2
file1_0.pdb,file1_60.pdb,file1_240.pdb,....file50_0.pdb,file50_60.pdb,file50_240.pdb..... again having some data.
is there a code possible that can copy data from each file from first example and paste it to its corresponding file in example2..? like from 1_0.pdb to file1_0.pdb...I hope iam not random and more clear...
With perl you could do something like
#!/usr/bin/perl -w
use strict;
my #filenames = qw(1_0.pdb 1_60.pdb 1_240.pdb);
for my $filename (#filenames) {
open(my $fr, '<', $filename) or next;
open(my $fw, '>>', "file$filename") or next;
local($/) = undef;
my $content = <$fr>;
print $fw $content;
close $fr;
close $fw;
}
EDIT:
Instead of listing all filnames in
my #filenames = qw(1_0.pdb 1_60.pdb 1_240.pdb);
you could do something like
my #filenames = grep {/^\d+_\d+/} glob "*.pdb";
Give this code a try:
use strict;
use warnings;
foreach my $file (glob "*.pdb") {
next if ($file =~ /^file/);
local $/ = undef;
my $newfile = "file$file";
open(my $fh1, "<", $file) or die "Could not open $file: " . $!;
open(my $fh2, ">>", $newfile) or die "Could not open $newfile: " . $!;
my $contents = <$fh1>;
print $fh2 $contents;
close($fh1);
close($fh2);
}
If you want to overwrite the contents of the files rather than appending, change ">>" to ">" in the second open statement.
This shell script will also work
foreach my_orig_file ( `ls *.pdb | grep -v ^file` )
set my_new_file = "file$my_orig_file"
cat $my_orig_file >> $my_new_file
end

Resources