How to check if today is a weekend using bash or even perl?
I want to prevent certain programs to run on a weekend.
You can use something like:
if [[ $(date +%u) -gt 5 ]]; then echo weekend; fi
date +%u gives you the day of the week from Monday (1) through to Sunday (7). If it's greater than 5 (Saturday is 6 and Sunday is 7), then it's the weekend.
So you could put something like this at the top of your script:
if [[ $(date +%u) -gt 5 ]]; then
echo 'Sorry, you cannot run this program on the weekend.'
exit
fi
Or the more succinct:
[[ $(date +%u) -gt 5 ]] && { echo "Weekend, not running"; exit; }
To check if it's a weekday, use the opposite sense (< 6 rather than > 5):
$(date +%u) -lt 6
case "$(date +%a)" in
Sat|Sun) echo "weekend";;
esac
This is actually a surprisingly difficult problem, because who is to say that "weekend" means Saturday and Sunday... what constitutes "the weekend" can actually vary across cultures (e.g. in Israel, people work on Sunday and have Friday off). While you can get the date with the date command, you will need to store some additional data indicating what constitutes the weekend for each locale if you are to implement this in a way that works for all users. If you target only one country, then the solution posed in the other answers will work... but it is always good to keep in mind the assumptions being made here.
Use Perl's localtime operator.
localtime
Converts a time as returned by the time function to a 9-element list with the time analyzed for the local time zone. Typically used as follows:
# 0 1 2 3 4 5 6 7 8
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
…
$wday is the day of the week, with 0 indicating Sunday and 3 indicating Wednesday.
For example:
$ date
Sun Aug 15 20:27:29 CDT 2010
$ perl -le 'my $wday = (localtime)[6];
print $wday >= 1 && $wday <= 5 ? "weekday" : "weekend"'
weekend
printf also has date
printf -v day '%(%a)T'
case $day in
Sat|Sun) echo "Hooray!";;
esac
https://ideone.com/wU7C0c - demo
I am not really sure if this is suited to this question but I wanted to share this it to help others out and this is the closest Stack question to what I was looking for.
This is a shell script that I use for starting an application when i boot my computer, the application cannot connect to its server over the weekend (its down for maintenance as the service doesn't run at weekends (forex trading application).
Information about this script, d is 1 to 7 (mon to sun) h is 24 time. You can adjust this to your own settings, maybe you have a midweek maintenance or any other cause. This is my first ever shell script, so I'm sure there is a better way and if anybody wants make edits, feel free I will review for acceptance (or somebody else may do it)
#!/bin/bash
d=$(date +%u)
h=$(date +%H)
case $d in
'5')
# Friday after 10pm
if (($h >= 22)) ; then
exit
fi
;;
'6')
# all day saturday
exit
;;
'7')
#sunday before 10pm
if (($h < 22)) ; then
exit
fi
;;
*)
# any other time run the program
;;
esac
I like this way of running programs on weekdays:
[[ $(date +%u) -lt 6 ]] && weekday-program
It is a bit tricky construction, but compact and easy to add.
Related
I'm writing a Perl program to check if and make sure that some system backup tasks were executed from crontab.
I need to read the crontab and interpret when it was supposed to run, in order to check if that backup was done. Here is an example.
00 03 * * 6 system_backup.sh
Let's suppose this task will generate a file called system_backup_20180510.iso
Then my idea was to store a "desirable date" into a var then compare with that date in the filename. The biggest issue is how to build that desirable date with crontab's day of month field filled up.
What you guys can suggest? Thanks
Note the 5th field: this only runs on Saturday.
Here's something you can do with GNU date:
$ date -d "-1 week saturday 03:00" "+%Y%m%d %H:%M:%S"
20180505 03:00:00
$ date -d "-w week saturday 03:00" "+%Y%m%d %H:%M:%S"
20180518 13:00:00
$ date -d "-2 week saturday 03:00" "+%Y%m%d %H:%M:%S"
20180428 03:00:00
the Schedule::Cron::Events suggestion implemented:
crontab -l | perl -MPOSIX=strftime -MSchedule::Cron::Events -lne '
$cron = Schedule::Cron::Events->new($_);
$prev = strftime("%F %T", $cron->previousEvent());
print "$prev => ", $cron->commandLine();
'
Im having some difficulty with this cron job. Running a job at 6:15PM every otherTuesday during March, June, September and December
What I have so far 15 18 1 3,6,9,12 2
Have a cron schedule for every Tuesday, and then make sure in the command that it only runs every other time. For example, we can use the date command to get the number of the week, so we can check if that week number is even.
15 18 * 3,6,9,12 2 [ $((`date +%V`%2)) -eq 0 ] && your_command
(untested)
Since the date in BusyBox is not as powerful as gnu date, I have problems to calculate the date of last saturday.
last_sat=`date +"%Y-%m-%d" -d "last saturday"`
only works fine with gnu date.
I've found something like this to calculate from Epoch
busybox date -D '%s' -d "$(( `busybox date +%s`+3*60 ))"
but my BusyBox (v1.1.0) doesn't recognize the -D argument.
Any suggestions?
For the last Saturday before today, under busybox 1.16:
date -d "UTC 1970-01-01 $(date +"%s - 86400 - %w * 86400"|xargs expr) secs"
How it works: take the current date in seconds, subtract one day, subtract one day times the number of the current weekday, then convert those seconds back to a date.
EDIT: after hacking together a build of 1.1, this works:
date -d "1970.01.01-00:00:$(date +"%s - 86400 - %w * 86400"|xargs expr)"
This working version is based on code-reading:
} else if (t = *tm_time, sscanf(t_string, "%d.%d.%d-%d:%d:%d", &t.tm_year,
&t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min,
&t.tm_sec) == 6) {
t.tm_year -= 1900; /* Adjust years */
t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
BusyBox's date command has been the topic of some discussion over the years. Apparently it doesn't always work as documented, and it doesn't always work the same as previous versions.
On a BB system I administer running BusyBox v1.01, I'm able to use the -d option with dates in the format MMDDhhmmYYYY.ss, and in no other format that I've tried. Luckily, output formats work as expected, presumably because date is using a proper strftime() according to comments in the source.
Here's my forward-and-reverse example:
[~] # busybox date '+%m%d%H%M%Y.%S'
090500152016.41
[~] # busybox date -d 090500152016.41
Mon Sep 5 00:15:41 EDT 2016
So .. what can we do with this? It seems that we can't do an arbitrary adjustment of seconds, as it only reads the first two digits:
[~] # busybox date -d 123119001969.65 '+%s'
65
[~] # busybox date -d 123119001969.100 '+%s'
10
Well, it turns out you can load the date fields with "invalid" numbers.
[~] # busybox date 090100002016
Thu Sep 1 00:00:00 EDT 2016
[~] # busybox date 093400002016
Wed Oct 4 00:00:00 EDT 2016
[~] # busybox date 09-200002016
Mon Aug 29 00:00:00 EDT 2016
So let's adjust the "day" field using something based on %w.
today=$(busybox date '+%m%d%H%M%Y')
last_sat=$(busybox date -d "${today:0:2}$( printf '%02d' $(( 10#${today:2:2} - 1 - $(busybox date '+%w') )) )${today:4}" '+%F')
This simply subtracts numbers in the second field (the 3rd and 4th characters of the date string). It obviously requires that your shell either be bash or understand bash-style math notation ($((...))). Math-wise, it should work as long as "last saturday" is within the same month, and it MAY work (I haven't tested it) with rollvers to the previous month (per the last test above).
Rather than jumping through these burning hoops, I recommend you just install a GNU date binary, and don't use busybox for this one binary. :-P
Good luck!
I have the following few lines in a batch file:
#echo off
echo Running dump...
"D:\wamp\bin\mysql\mysql5.5.16\bin\mysqldump" --host="localhost" --user="****" --password="****" database> "D:\wamp\backup\mysql\"back.%date:~0,2%.sql
echo Done!
Supposedly, it should create a backup file with today's day as 01, 02, 03, ..., 31, that is,
back.01.sql
back.02.sql
back.03.sql
When I run it from CMD, it actually creates it as expected, but when it is run from the scheduler it looks like:
back.Mo.sql
back.Tu.sql
back.We.sql
What date format should I use to ensure it actually created with number of the day of the month?
Working with dates and times in Windows batch is a pain.
The most robust solution is to use WMIC to get the local date and time. It returns a value in the following format:
YYYYMMDDhhmmss.dddddd-ttt
YYYY = year
MM = month
DD = day
hh = hour in 24 hour format
mm = minutes
ss = seconds
dddddd = fractional seconds
ttt = time zone (minutes difference from Greenwich Mean Time)
So you can use the following to get the current day of the month in a variable
Edit - corrected starting substring location from 7 to 6
set curDate=
for /f "skip=1" %%x in ('wmic os get localdatetime') do if not defined curDate set curDate=%%x
set day=%curDate:~6,2%
The big advantage of this technique is it will work on any Windows machine in the world, regardless of the locale settings.
Here is your code with the technique inserted
Edit - corrected starting substring location from 7 to 6
#echo off
echo Running dump...
set curDate=
for /f "skip=1" %%x in ('wmic os get localdatetime') do if not defined curDate set curDate=%%x
set "day=%curDate:~6,2%"
"D:\wamp\bin\mysql\mysql5.5.16\bin\mysqldump" --host="localhost" --user="****" --password="****" database> "D:\wamp\backup\mysql\back.%day%.sql"
echo Done!
Just setup regional settings dd.MM.yyyy for the account under which your task is run. (use control panel or registry HKCU\Control Panel\International\sShortDate for Windows XP at least.
After figuring out (via SO, of course) that the error for a bad $ftp = Net::FTP->new() call is in $# while subsequent errors can be obtained by $ftp->message(), I'm striking a small problem.
My code is basically:
while (1) {
# Wait for cycle start, then get file list into #filelist.
foreach $file (#filelist) {
my $ftp = Net::FTP->new ($host);
if (! $ftp) {
logError ("Could not connect to host [$host]: $#");
return;
}
# More FTP stuff below with $ftp->message() error checking.
$ftp->quit();
}
}
Aside: yes, I know I can probably do this in one FTP session, but there are good reasons for leaving it in separate sessions at the moment.
Now this is being called in a loop, once per file, all going to the same host, but I'm getting a slightly different behaviour on the first attempt in most cycles. The script is a long-running one, with each cycle starting on the hour and half hour so it's not some issue with the first ever attempt after program start, since it happens on cycles other than the first as well.
Now I know that these connections should fail, simply because the machines I'm trying to access are not available on my development network.
The trouble is that the errors coming out in the log file are:
E 2012-02-05 18:00:13 Could not connect to host [example.com]:
E 2012-02-05 18:00:13 Could not connect to host [example.com]:
Net::FTP: connect: Connection refused
E 2012-02-05 18:00:14 Could not connect to host [example.com]:
Net::FTP: connect: Connection refused
As you can see, the $# variable seems to be not populated the first file of the cycle. I've edited this question slightly since I've just noticed the latest cycle had all three lines with the error message. Going back over the logs with the command:
grep refused logfile | awk '{print substr($3,1,5)}' | uniq -c
to get the dates and counts, turns up the following statistics:
3 11:00
3 11:30
3 12:00
3 12:30
3 13:00
3 13:30
2 14:00
3 14:30
3 15:00
3 15:30
3 16:00
2 16:30
2 17:00
2 17:30
2 18:00
2 18:30
2 19:00
3 19:30
indicating that some have the correct count of error messages but not all.
I'm wondering if anyone knows why this may be the case.
Try upgrading http://cpansearch.perl.org/src/GBARR/libnet-1.22_01/Changes says
libnet 1.22_01 -- Mon May 31 09:40:25 CDT 2010
*Set $# when ->new returns undef
If you're using a version of libnet prior to 1.22_01, it had a small bug in the new function in regards to responses that didn't start with a code.
For example, FTP.pm 2.77 which is from libnet 1.21 has the following snippet:
unless ($ftp->response() == CMD_OK) {
$ftp->close();
$# = $ftp->message;
undef $ftp;
}
With FTP.pm 2.77_2 from libnet 1.22_01, this is changed to:
unless ($ftp->response() == CMD_OK) {
$ftp->close();
# keep #$ if no message. Happens, when response did not start with a code.
$# = $ftp->message || $#;
undef $ftp;
}
Is there anything going on between the ->new call and printing the $#? It can overwrite the value of $#, so if it is neccesary, store the value for later use:
my $ftp = Net::FTP->new ($host);
my $potential_error = $#;
$whatever_that->can_call(eval => 'inside');
if (! $ftp) {
logError ("Could not connect to host [$host]: $potential_error");
}