Unexpected output from perl script - perl

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.

Related

Perl variable that takes different values

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.

Perl: Dirhandle,

I was reading how-do-i-read-in-the-contents-of-a-directory and wanted to find out more about doing it without opening and closing directories as shown in #davidprecious' answer. Tried to read up on DirHandle (hoped for more explanation and example) and several other places simply redirected me to the same perldoc page. Still unsure about where to stipulate the path to read.
Say if I wanted the contents of "E:\parent\sub1\sub2\" and put that into a string variable like $p, where do I mention $p when using Dirhandle?
Would appreciate some guidance. Thanks.
Personally, I'd suggest that's too complicated, and what you probably want is glob:
#!/usr/bin/env perl
use strict;
use warnings;
foreach my $file ( glob "E:\\parent\\sub1\\sub2\\*" ) {
print $file,"\n";
}
Although note - glob gives you the path to the file, not the filename. That's (IMO) generally more useful, because you can just pass the result to open, where if you're doing a readdir you get a file name and need to stick a path on it.
However if you do want to persist with doing it via DirHandle:
#!/usr/bin/env perl
use strict;
use warnings;
use DirHandle;
my $dir_handle = DirHandle -> new ( "C:\\Users\\Rolison\\" );
while ( my $entry = $dir_handle -> read ) {
print $entry,"\n";
}
Don't use $p as a variable name - single character variable names are almost always bad style.
It's probably worth pointing out that Windows is quite happy to use forward slashes (/) as directory separators - which avoids having to have all those ugly double backslashes.
my $dir_handle = DirHandle->new('E:/parent/sub1/sub2/');
while ( my $entry = $dir_handle->read ) {
say $entry;
}

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 to find if file is readable by all?

How to find if a file is readable by everyone in UNIX?
The (relatively) modern solution: use File::stat, a core module since 5.004, and Fcntl, which has always been in Perl 5. See also perldoc -f stat.
use strict;
use warnings;
use File::stat;
use Fcntl qw(:mode);
...
my $mode = stat($filename)->mode;
my $allCanRead = ($mode & S_IRUSR) # User can read
&& ($mode & S_IRGRP) # Group can read
&& ($mode & S_IROTH); # Others can read
From perldoc:
$mode = (stat($filename))[2];
printf "Permissions are %04o\n", $mode & 07777;
To extract read-for-others bit you can do
print "read for everyone" if $mode & 4; # pick bit 2 from mode
Use the stat function.

How can I calculate the MD5 hash of a wav file in Perl?

I have a wav file and I need to calculate the MD5 hash of its contents. How can i do that using Perl?
There is module for it: Digest::MD5::File. With it the code is simplified to:
use Digest::MD5::File qw( file_md5_hex );
my $md5 = file_md5_hex( $some_file_name );
Sure you can. Just look for Digest::MD5 for the hashing part, and any WAV-related module if you want to hash a specific part of the file (skipping metadata, for example).
Using the Digest::MD5
use Digest::MD5 qw(md5);
my $hash;
{
local $/ = undef;
open FILE, "$wav_file_name";
binmode FILE;
my $data = <FILE>;
close FILE;
$hash = md5($data);
}
or you could use the OO interface:
use Digest::MD5;
open FILE, "$wav_file_name";
my $ctx = Digest::MD5->new;
$ctx->addfile (*FILE);
my $hash = $ctx->digest;
close (FILE);
The following, based on a comment by user hexten, is working for me and should perform better than the answers that slurp the file:
use Digest::MD5 qw( md5_hex );
open my $fh, '<', $file;
my $md5 = Digest::MD5->new->addfile($fh)->hexdigest;
close $fh;
The (currently) top-voted answer suggests using Digest::MD5::File, but that does not work for me at least on the latest Windows build of ActiveState Perl, and the link in the answer is now dead.
Simply use Digest::MD5.
Depending upon your needs, Perceptual Hashing may be interesting too, by the way. It allows you to compare files by comparing their hashes (similar contents have similar hashes). However there still isn't any perl implementation AFAIK.
Using File::Slurp with Digest::MD5:
#!/usr/bin/perl
use strict;
use warnings;
use Digest::MD5 qw(md5_hex);
use File::Slurp;
my ($input) = #ARGV;
write_file "$input.md5", md5_hex(scalar read_file $input, binmode => ':raw'), "\n";
Or Digest::file -
Perl v5.20.2 in Debian Jessie
# Poor mans "md5sum" command
use Digest::file qw(digest_file_hex);
for (#ARGV) {
print digest_file_hex($_, "MD5"), " $_\n";
}