error "undefined subroutine" with perl File::Copy mkpath - perl

I keep on getting errors on this routine for line 51 where i user the mkpath - I tried putting the File::Copy at the top of the subroutine ( line 38 )but still get error -
use warnings;
use DBI;
use File::Copy;
unshift #INC, "/production/lib";
require "config.pl";
$configFile = "/production/cfg/syncUsers.cfg";
readConfig($configFile);
doBackup($prefs{passwdFile});
# generatePasswdFile("tmpusers");
# getUsers($prefs{dbUser}, $prefs{dbPass}, $prefs{dbSid});
# copyPasswdFile($prefs{passwdFile});
# doBackup - backup the existing
sub doBackup {
#use File::Copy;
my (#theMonth, $month, $day, $year) = "";
if (!-e $prefs{passwdFile}) {
print "Password file: $prefs{passwdFile} does not exist. No backup being made.\n";
}
else {
print "$prefs{passwdFile} found. Performing backup.\n";
($mday, $mon, $year) = (localtime(time))[3 .. 5];
#theMonth = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
$month = $theMonth[$mon];
$day = sprintf("%02d", $mday);
$year = sprintf("%04d", $year + 1900);
$backupDir = "$prefs{backupDir}/$year$month$day/webstart";
print "$backupDir\n";
mkpath($backupDir); # Line 51
if (-e "$backupDir") {
move($prefs{passwdFile}, $backupDir);
}
else {
print "The backup directory was not created\n";
}
if (-e "$backupDir/etc-users") {
print "Backup successful. Generating file.\n";
}
else {
print "Backup failed. Exiting.\n";
exit 1;
}
}
}
and this is the result:
/production/web/users/etc-users1 found. Performing backup.
/production/archive/2013Nov19/webstart
Undefined subroutine &main::mkpath called at ./testbackup.pl.seco line 51.
the module is on the host:
bash-3.00$ perldoc -l File::Copy
/usr/local/perl5.8.8/lib/5.8.8/File/Copy.pm
bash-3.00$

File::Copy does not have mkpath, but
File::Path does.
Change:
use File::Copy;
to:
use File::Path;

Does File::Copy autoexport mkpath? Or maybe you need either
use File::Copy qw/ mkpath /;
or to call it as
File::Copy::mkpath()

Related

Perl Get File Last Modified Date Time No Module

I'm creating a script where I need to get the Last Modified Date of the files
I checked this thread How do I get a file's last modified time in Perl?
So I used the script below to get the last modified, at first it was working but when I try to run it again, the timestamp returns 00:00 January 1, 1970.
Why is that happening and how can I get the correct last modified date and time?
my $dir = '/tmp';
opendir(DIR, $dir) or die $!;
#content=readdir(DIR);
foreach(#content)
{
next unless ($_ =~ m/\bfile.txt|file2.csv\b/);
my $epoch_timestamp = (stat($_))[9];
my $timestamp = localtime($epoch_timestamp);
$f_detail = $_ .' '.$timestamp;
print "$f_detail\n";
}
closedir(DIR);
exit 0;
When I tried to run the perl, I will get this result
file.txt Thu Jan 1 00:00:00 1970
file2.csv Thu Jan 1 00:00:00 1970
Ok, last update, it is working now, I try to run all of the scripts you've given to me, standalone script. I found what's causing the default time, see the script below, I remove that in my program and it works, didn't notice this at first, sorry. But still, it feels weird because I was sure that it is working when I first run it, but now it is working so yeah thank you guys!
if (($month = ((localtime)[4] + 1)) < 10)
{
$month = '0' . $month;
}
if (($day = ((localtime)[3])) < 10)
{
$day = '0' . $day;
}
if (($year = ((localtime)[5]+1900)) >= 2000)
{
if (($year = $year - 2000) < 10)
{
$year = '0' . $year;
}
}
else
{
$year = $year - 1900;
}
$date = $month . $day . $year;
readdir returns file names without the full path. You need to prepend the path manually:
for (#content) {
next unless /^(?:file\.txt|file2\.csv)\z/;
my $epoch_timestamp = (stat("$dir/$_"))[9];
# ~~~~~~~~~
Also note how I changed the regex to match the file names.
If you have a directory name, and you want to see if some files whose names you already know exist in that directory, there's really no need for opendir/readdir - that's more helpful if you don't know the filenames ahead of time. When you do, you can just build a path using both parts and use file test operators/stat/etc. on it.
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;
my $dir = '/tmp';
my #files = qw/file.txt file2.csv/;
for my $file (#files) {
# Better to use File::Spec->catfile($dir, $file), but your question
# title said no modules...
my $name = "$dir/$file";
if (-e $name) { # Does the file exist?
# _ to re-use the results of the above file test operator's stat call
my $epoch_timestamp = (stat _)[9];
my $timestamp = localtime $epoch_timestamp;
say "$file $timestamp";
}
}
Example execution:
$ perl demo.pl
file.txt Tue Feb 8 07:26:07 2022
file2.csv Tue Feb 8 07:26:10 2022
Following demo code utilizes glob to obtain modification time for specified files in a directory.
use strict;
use warnings;
use feature 'say';
my $dir = '/tmp';
my #files = qw(file.txt file2.csv);
my $mask = join ' ', map { "$dir/$_" } #files;
say "$_\t" . localtime((stat($_))[9]) for glob($mask);

Perl Date Comparison Query

I'm trying to output "not ok" if the date provided within an input file is greater than one day from "today" using Perl version 5.8.8.
Initializing with "./code.sh < test.txt" works fine, when test.txt contains the following data:
07/02/2020 08/02/2020
When I rehash the code below to try an use "today's date" as a variable, and only have one date within the input file I get the following error:
Use of uninitialized value in concatenation (.) or string at code.sh line 27, <> line 1
Working code (with two dates in the input file):
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;
#my $date = localtime->strftime('%d/%m/%Y');
#print "$date";
my $format = '%d/%m/%Y';
while (<>) {
chomp;
my ($str1, $str2) = split;
# my ($date, $str2) = split;
# my $dt1 = Time::Piece->strptime($date, $format);
my $dt1 = Time::Piece->strptime($str1, $format);
my $dt2 = Time::Piece->strptime($str2, $format);
# print "$date / $str2 ";
print "$str1 / $str2 ";
if ($dt2->julian_day - $dt1->julian_day ==1) {
print "ok\n";
} else {
print "not ok\n";
}
}
Broken code (with one date within the input file):
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;
my $date = localtime->strftime('%d/%m/%Y');
print "$date";
my $format = '%d/%m/%Y';
while (<>) {
chomp;
# my ($str1, $str2) = split;
my ($date, $str2) = split;
my $dt1 = Time::Piece->strptime($date, $format);
# my $dt1 = Time::Piece->strptime($str1, $format);
my $dt2 = Time::Piece->strptime($str2, $format);
print "$date / $str2 ";
# print "$str1 / $str2 ";
if ($dt2->julian_day - $dt1->julian_day ==1) {
print "ok\n";
} else {
print "not ok\n";
}
}
Not quite sure what I'm doing wrong...
Any help is appreciated
Please pay more attention when you type your code, your sample had a few miss-types
#!/usr/bin/perl
#
# vim: ai:ts=4:sw=4
#
use strict;
use warnings;
use feature 'say';
use Time::Piece;
my $format = '%d/%m/%Y';
my $date = localtime->strftime($format);
say "Today is: $date\n";
my #str_dates = <DATA>;
chomp(#str_dates);
my $date1 = Time::Piece->strptime($str_dates[0], $format);
my $date2 = Time::Piece->strptime($str_dates[1], $format);
my $days_diff = $date2->julian_day - $date1->julian_day;
my $msg = ($days_diff == 1) ? "ok" :"not ok";
say "$date2 :: $date1 => $msg";
say "$date2 :: $date1 = $days_diff day(s) apart";
__DATA__
07/02/2020
08/02/2020
Output
Today is: 07/02/2020
Sat Feb 8 00:00:00 2020 :: Fri Feb 7 00:00:00 2020 => ok
Sat Feb 8 00:00:00 2020 :: Fri Feb 7 00:00:00 2020 = 1 day(s) apart
NOTE: I would recommend if you use:
Windows OS
notepad++
Linux OS vim
vim better use with options: syntax on, ai,ts=4,sw=4

Move the files older than three hours to archive folder without overwriting existing files

The below script will move the files having modification time older than three hours from /tmp/test1 folder to /data/ARCHIVE folder.
The issue is that if the ARCHIVE folder already has a file with same name as in the test1 folder it will overwrite them, which is unwanted.
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;
use File::Copy;
my $dstdir = '/data/ARCHIVE/';
#ARGV = ("/tmp/test1") unless #ARGV;
print STDERR "Begin # ", scalar localtime, "\n";
find(
sub {
if ( -f $_ && -M _ >= 3 / 24 ) {
print STDERR "Moving '$_'\n";
move( $File::Find::name, $dstdir ) or die "$!\n";
}
},
#ARGV
);
print STDERR "Ended # ", scalar localtime, "\n";
1;
Add the epoch to the file name. But don't run your code more than once a second.
my $now = strftime( '%Y%m%d%H%M%S', localtime );
find(
sub {
if ( -f $_ && -M _ >= 3 / 24 ) {
print STDERR "Moving '$_'\n";
my $dst = "$dstdir/$_.$now";
move( $File::Find::name, $dst ) or die "$!\n";
}
},
#ARGV
);

Issue with Perl File::stat output, need to show date

I am having an issue with getting File::stat to output the last modified date of the file. This is my code so far:
#!/usr/bin/perl
use Time::localtime;
use File::stat;
use warnings;
use File::Find;
my $dirloc = 'E:\tmp\testdir';
sub find_txt {
my $F = $File::Find::name;
if ( ! -d $F && $F =~ /.tar|.exe|.zip/ ) {
my #result = $F;
foreach my $result (#result){
my $timestamp;
$timestamp = (stat("$result"))->[9] or die "No $_: $!";
print "$result : $timestamp\n";
}
}
}
find({wanted => \&find_txt}, $dirloc);
It is outputing something like this:
C:/tmp/testdir/foo/bar/test.tar : 1415305933
I need it to output instead (date format doesn't have to be what is listed, i just want to see the date):
C:/tmp/testdir/foo/bar/test.tar : 11/07/2014
I know that the output it is giving me is the time since epoch but I thought stat was supposed to give the date. Am I doing something wrong? Thanks!
edit: I have tried localtime, and i get: Time::tm=ARRAY(0x245b220), not sure what is happening there
You can use the localtime (Note: not Time::localtime) function to convert the timestamp into something useful
my $date = localtime $timestamp
which will make it a human readable string like Fri Nov 7 15:33:00 2014
Or you can use it in a list context to spit it into individual fields:
my($sec, $min, $hour, $day, $month, $year, $weekday, $yearOfDay, $isDST) = localtime $timestamp

How do I convert epoch time to normal time in Perl?

I am attempting to write a Perl script that parses a log where on each line the second value is the date. The script takes in three arguments: the input log file, the start time, and the end time. The start and end time are used to parse out a certain value on each line that that falls between those two times. But to properly run this I am converting the start and end time to epoch time. The problem I am having is that to convert the loops 'i' value back to normal time to compare against the log file. After running localtime($i) I print the value and only see a reference printed not the actual value.
Here is the script I have so far (it is a work in progress):
#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
use Time::localtime;
use File::stat;
my $sec = 0;
my $min = 0;
my $hour = 0;
my $mday = 0;
my $mon = 0;
my $year = 0;
my $wday = 0;
my $yday = 0;
my $isdst = 0;
##########################
# Get the engine log date
##########################
my $date = `grep -m 1 'Metric' "$ARGV[0]" | awk '{print \$2}'`;
($year,$mon,$mday) = split('-', $date);
$mon--;
#########################################
# Calculate the start and end epoch time
#########################################
($hour,$min,$sec) = split(':', $ARGV[1]);
my $startTime = timelocal($sec,$min,$hour,$mday,$mon,$year);
($hour,$min,$sec) = split(':', $ARGV[2]);
my $endTime = timelocal($sec,$min,$hour,$mday,$mon,$year);
my $theTime = 0;
for (my $i = $startTime; $i <= $endTime + 29; $i++) {
#print "$startTime $i \n";
$theTime = localtime($i);
#my $DBInstance0 = `grep "$hour:$min:$sec" "$ARGV[0]"`;# | grep 'DBInstance-0' | awk '{print \$9}'`;
#print "$DBInstance0\n";
print "$theTime\n";
}
print "$startTime $endTime \n";
The output looks like:
Time::tm=ARRAY(0x8cbbd40)
Time::tm=ARRAY(0x8cbc1a0)
Time::tm=ARRAY(0x8cbbe80)
Time::tm=ARRAY(0x8cbc190)
Time::tm=ARRAY(0x8bbb170)
Time::tm=ARRAY(0x8cbc180)
Time::tm=ARRAY(0x8cbbf30)
Time::tm=ARRAY(0x8cbc170)
Time::tm=ARRAY(0x8cbc210)
Time::tm=ARRAY(0x8cbc160)
1275760356 1275760773
I only have access to the core Perl modules and am unable to install any others.
You can use ctime, depending on your definition of "Normal time":
Example code:
use Time::Local;
use Time::localtime;
my $time=timelocal(1,2,3,24,6,2010);
print "$time\n";
$theTime = ctime($time);
print "$theTime\n";
Result:
1279954921
Sat Jul 24 03:02:01 2010
Also, you don't need to use Time::Localtime (which is why you get Time::tm instead of a standard array/string from Perl's internal localtime):
use Time::Local;
my $time=timelocal(1,2,3,24,6,2010);
print "$time\n";
$theTime = localtime($time);
print "$theTime\n";
1279954921
Sat Jul 24 03:02:01 2010
Don't forget to subtract 1900 from the year!
Remember that in scalar context, localtime and gmtime returns a ctime-formatted string, so you could use it as in the following. If that's unsuitable, you might want to use strftime from the POSIX module.
#! /usr/bin/perl
use warnings;
use strict;
use Time::Local;
my $start = "01:02:03";
my $end = "01:02:05";
my $date = "2010-02-10";
my($year,$mon,$mday) = split /-/, $date;
$mon--;
$year -= 1900;
my($startTime,$endTime) =
map { my($hour,$min,$sec) = split /:/;
timelocal $sec,$min,$hour,$mday,$mon,$year }
$start, $end;
for (my $i = $startTime; $i <= $endTime + 29; $i++) {
print scalar localtime($i), "\n";
}
print "$startTime $endTime \n";
Tail of the output:
Wed Feb 10 01:02:26 2010
Wed Feb 10 01:02:27 2010
Wed Feb 10 01:02:28 2010
Wed Feb 10 01:02:29 2010
Wed Feb 10 01:02:30 2010
Wed Feb 10 01:02:31 2010
Wed Feb 10 01:02:32 2010
Wed Feb 10 01:02:33 2010
Wed Feb 10 01:02:34 2010
1265785323 1265785325