Perl variable that takes different values - perl

I need to upload files with different names in the same format like this:
file_name_yyyy-mm-dd_code.txt
How can I write it in Perl?
Right now I can do this:
#!/usr/bin/perl
use warnings;
use strict;
use Config::Simple;
use File::Basename;
use Getopt::Long;
use Pod::Usage;
use Net::Google::Drive::Simple;
use POSIX 'strftime';
use Storable;
# my $date = strftime '%m-%d-%Y', localtime;
# for testing purpose, use specific date
my $date = '2018-07-16';
my $code;
# $code will change
my $gd = Net::Google::Drive::Simple->new();
my ($p1, $folder) = $gd->children("Test");
$folder = <folder id>;
$gd->file_upload("testfile_${date}_${code}.txt", $folder);
and it uploads files with this format in the same folder as the perl file:
file_name_yyyy-mm-dd.txt
but it doesn't upload files with this format (which I need to do): file_name_yyyy-mm-dd_somecode.txt
For example:
file_name_2018-07-16_code1.txt or file_name_2018-07-16_code2.txt
I have absolutely no experience with Perl so I don't even know where to look.

The problem is that, in
"file_name_$date_$code.txt"
$date_ is a valid variable name, but not the one you want. Delineate the identifiers with braces, like this
"file_name_${date}_${code}.txt"
Or you can use sprintf, like this
sprintf 'file_name_%s_%s.txt', $date, $code
which produces the same result

You still haven't been very clear in describing what you want, but I wonder if you're looking for glob().
for my $file (glob("file_name_${date}_*.txt")) {
$gd->file_upload($file, $folder);
}
You can adjust the string you pass to glob() so it gives you whatever files your really want.

Related

Input parameter for perl CGI script

I need some insight on my Perl CGI script.
First of all all this is running under webmin so i'm doing a custom module.
I'm calling a CGI Perl script passing 2 parameter from another Perl CGI. The link I'm calling is in the following format:
http://IP:8080/foobar/alat.cgi?sysinfo=xxxxxxx&SR=yyyyyyyy
The alat.cgi script look like this
#!/usr/bin/perl
use CGI qw(:standard);
ReadParse();
$q = new CGI;
my $dir = $in->param('SR');
my $s = $in->param('sysinfo');
ui_print_header(undef, $text{'edit_title'}.$dir, "");
print $dir."<br>";
print $s"<br>";
The only output I get printed is the value of $dir and $s seems to be empty.
What am I doing wrong?
As #Сухой27 said, add use strict;, but also use warnings; to the top of your script, right below the shebang (#!/usr/bin/perl) line. Those will tell you about syntax errors and other stuff where Perl is doing something other than you might intend.
With CGI (which is btw not part of the Perl core in the latest 5.22 release any more) and the object oriented approach you are tyring to take, you don't need to use ReadParse(). That is an abomination left in from Perl 4's cgilib.pl times.
I don't know what your ui_print_header function does. I'm guessing it outputs a bunch of HTML. Are you sure you defined it?
With fixing all your syntax errors and using modern syntax, your program would look like this. I'll break down what is happening for you.
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
my $q = CGI->new;
my $dir = $q->param('SR');
my $s = $q->param('sysinfo');
# you need to declare this to use it below
my %text = ( edit_title => 'foo' );
# we declare this sub further down
ui_print_header(undef, $text{'edit_title'} . $dir, q{});
print $dir . '<br />';
print $s . '<br />';
sub ui_print_header {
my ( $foo, $title, $dir, $bar ) = #_;
# do stuff here...
}
Let's look at some of the things I did here.
Saying new CGI as the CGI docs suggest is fine, but since we are using the OOP way you can use the more common CGI->new. It's the same thing really, but it's consistent with the rest of the OOP Perl world and it's more clear that you are calling the new method on the CGI package.
If you have $q, keep using it. There is no $in.
Declare all your variables with my.
Declare %text so you can use $text{'edit_title'} later. Probably you imported that, or ommitted it from the code you showed us.
Declare ui_print_header(). See above.
q{} is the same as '', but it's clearer that it's an empty string.
thank you everyone for the very quick answer, and as I was suspecting I just had some silly mistake.
Adding here the corrected code that now works
#!/usr/bin/perl
# Run alat on selected sysinfo and allow display of output
#use strict;
use diagnostics;
require 'recoverpoint-lib.pl';
use CGI qw(:standard);
ReadParse();
my $q = new CGI;
my $dir = $q->param('SR');
my $s = $q->param('sysinfo');
ui_print_header(undef, $text{'edit_title'}.$dir, "");
print $dir."<br>";
print $s."<br>";
Just to clarify for some of previous answer, this is a custom module of webmin so variable $text is imported and function ui_print_header is a webmin defined one, it basically print the page header in HTML
As you enable strict and warnings you can easily know the errors.Also you should check Apache error logs, I think the script should be like this:
#!/usr/bin/perl
use CGI qw(:standard);
use strict;
use warnings;
ReadParse();
my $q = new CGI;
my $dir = $q->param('SR');
my $s = $q->param('sysinfo');
ui_print_header(undef, $text{'edit_title'}.$dir, "");
print $dir."<br>";
print $s."<br>";

How do I open a file in Perl using a search path (e.g. $PATH)?

I have a situation in which I am reading filenames from a file in Perl. These filenames never have a directory associated with them, only a file name (e.g. "foo.bar"). I need to search the equivalent of gmake's VPATH (or a shell's PATH) for that file.
I figure I can split the PATH at the colons, concatenate each segment to the file, and see if it exists. Is there an easier way to do this, though?
What's so uneasy in it?
#! /usr/bin/perl
use warnings;
use strict;
use List::Util qw{ first };
sub find_in_path {
my $file = shift;
return first { -f } map "$_/$file", split /:/, $ENV{PATH}
}
print find_in_path('grep'), "\n";

Unexpected output from perl script

The following script produces no output:
use File::stat;
use Time::localtime;
my $filename = 'c:\testfile';
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks)
= stat($filename);
print("$mtime");
c:\testfile exists.
I've seen several answers on SO -- this, for example -- which seem to suggest that the array returned by stat() should have something meaningful in it, but I haven't seen that to be the case in practice.
This is 64 bit ActivePerl on Windows 7.
Does stat not do what those answers seemed to imply, or do Perl's file date/time functions not work under Windows (or 64 bit Windows, or some such?)
This works fine:
#!perl
use strict;
use warnings;
my $filename = 'c:\Users\username\Documents\asdf23rasdf.pl';
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev,
$size, $atime, $mtime, $ctime, $blksize, $blocks
) = stat($filename);
print($mtime);
As alluded to in the comments - Perl's built-in stat works like the above. You don't need to use File::Stat or File::stat in order to do that. They just provide different interfaces to the same functionality.
If you want to do it with File::stat it goes like this:
use File::stat;
my $filename = 'c:\Users\username\Documents\asdf23rasdf.pl';
my $stats = stat($filename);
print( $stats -> mtime);
File::stat replaces stat with one that has a different interface. Remove use File::stat; or use its stat appropriately.

perl to open csv file with dynamic date in it?

How can I open a CSV file with a date that changes each day, where the date format is yyyy for year, dd for day and mmm for a 3 letter month.
This is as far as I've got
#!/usr/bin/perl
use strict;
use warnings;
#Set-up Input Files
#Inputfile
$INFILE = "C:\\DBR_%yyyy\\%b\\Failures_input%d%h\\.csv";
#Open input file for reading
open (INPUT,"$INFILE") or die " cannot open $INFILE ";
It is very unclear what you are asking for, and you don't mention %d and %h in your pattern.
If you want to open the latest CSV file then you need to do a nested search of the path, finding the latest date and time.
Here is something that may help. This code generates the path to the file that would be created for the current date and time. It uses the Time::Piece module, which is part of core Perl and shouldn't need installing. By default it overloads the localtime operator so that it returns a Time::Piece object in scalar context. That allows the module's utility methods to be applied directly.
use strict;
use warnings;
use Time::Piece;
my $failures_file = localtime->strftime('C:\DBR_%Y\%b\Failures_input%d%b.csv');
my $invoices_file = localtime->strftime('C:\%Y\%b\invoices%d%b.csv');
print $failures_file, "\n";
print $invoices_file, "\n";
output
C:\DBR_2014\Mar\Failures_input17Mar.csv
C:\2014\Mar\invoices17Mar.csv
However I think it is more likely that you want the name of the latest file with a path of that form, which is a little more complex (and a dreadful system design). Please verify your requirement and we will be able to help you further.
I wanted to write an answer about the localtime Perl function, but its documentation is so complete that it even includes stuff about the three-letter abbreviations.
A few remarks on your string literal for the filename:
You can use single forward slashes, even on Windows
You don't have to escape the dot with a backslash
You can "interpolate" variables into strings: "DBR_$yyyy" if $yyyy is a variable.
I second SzG's general recommendations.
The following shows how to add the date formatting to your filename using two core modules.
Using Time::Piece (in Perl core since version 5.8):
use Time::Piece;
use strict;
use warnings;
my $infile = localtime->strftime('C:\DBR_%Y\%b\Failures_input%d.csv');
Or using POSIX and strftime if you're working on an ancient box. To find the available specifiers, just google strftime:
use POSIX qw(strftime);
use strict;
use warnings;
my $infile = strftime 'C:\DBR_%Y\%b\Failures_input%d.csv', localtime;
Outputs:
C:\DBR_2014\Mar\Failures_input16.csv

perl - File::Basename->fileparse returns "File::Basename"

For some reason my code is doing this wierd thing where fileparse only prints (literally) File::Basename
use strict;
use warnings 'all';
use File::Basename;
...
my $fileName = File::Basename->fileparse($filePath);
print("$filePath\n");
print("$fileName\n");
And output is:
a/b/c/d.bin
File::Basename
What did I do wrong?
The fileparse is not a method; it is a function. This function is exported by default, so you actually want to do
use File::Basename;
my $fileName = fileparse($filePath);
You have used is as a method call. Here File::Basename->fileparse($filePath) is equivalent to
fileparse("File::Basename", $filePath)
because in a method invocation, the invocant (usually an object; here the package name) becomes the first argument. This is wrong, as it treats "File::Basename" as the path to parse, and the following arguments as a list of valid suffixes.
If you want to use the fileparse function without exporting it to your namespace, you could
use File::Basename (); # note empty parens that supress the import
File::Basename::fileparse(...); # use fully qualified name