Schedule Cron to skip first Saturday of every month - linux

I need a cron to skip the first Saturday of every month. I know we can run on specific days using the below command, but is there a way to skip on a particular day for every month?
//To run on first Monday of every month
0 2 * * 1 [ date '+\%m' == date '+\%m' -d "1 week ago" ] || /path/to/command

Is your command a binary file or just script?
How about the idea to add something like that in the beginning:
[ $(date | awk '{print $1}') == "Sat" ] && exit 1 || { \
# your code here
...
}

Since there seem to be no option in Cron.
I'm going with script for the above need.
**if [ $(date +%d) -le 7 ] && [ $(date +%u) -eq 1 ] ;**
[ $(date +%d) -le 7 ] - Checks if the days fall in first 7 days of month
[ $(date +%u) -eq 6 ] - Checks if day is equal to Saturday
Thanks.

The following works in cron (don't forget to escape the %):
0 2 * * * [[ `date '+\%u'` -ne '6' && `date '+\%d'` -lt '8' ]] || [[ `date '+\%d'` -gt '7' ]] && /path/to/command
The logic is :
If the day is not a Saturday and the day of the month is 1-7, execute the command
If the above is not correct, check if the day of the month is bigger than 7, if so execute
Another way would be to invert the logic :
0 2 * * * [[ ! ( `date '+\%u'` -eq '6' && `date '+\%d'` -lt '8' ) ]] && /path/to/command
The logic is :
If the day is not the first Saturday, execute the command
man 5 crontab
The "sixth" field (the rest of the line) specifies the command to be run. The entire command portion of the line, up to a newline or
a "%" character, will be executed by /bin/sh or by the shell specified in the SHELL variable of the cronfile. A "%" character in the command, unless escaped with a backslash (\), will be changed into newline characters, and all data after the first % will be sent to the command as standard input.

Related

It does not return the expected output [duplicate]

This question already has answers here:
Compare Numbers not working properly (Bash Script in Hacker Rank)
(2 answers)
Closed last year.
The intention of my script is to print the users who have inactive days of more than 30. This is my script:
#!/bin/bash
max=30
grep -E ^[^:]+:[^\!*] /etc/shadow | awk -F: '{print $1" "$7}' | while read user days
do
if [ $days -gt $max ]
then
echo $user
echo $days
fi
done
I created 2 users, test and test2 each with 30 days and 50 days inactivity respectively. This script returns me both when I only need to print test2 with 50 days of inactivity.
I think you are making this more complicated than needed.
Since you already have awk in your pipe, that can replace grep and compare to max.
Simple example.
Given:
cat file
dawg 2 3 4 5 6 45
boosh 2 3 4 5 6 25
You can do:
max=30
awk -v max="$max" '$7>max{print $1, $7}' shadow
dawg 2 3 4 5 6 45
I left out the grep portion but you can either keep that as a pipe (if it is working) or integrate into the awk.
If you want to compare two integers in Bash, you either need to use the correct test, which is (( arithmetic context ))
$ (( 1>2 )); echo $?
1
$ (( 10>2 )); echo $?
0
# 0 means TRUE
or the correct operator which is [ -gt ]:
$ [ 10 -gt 2 ]; echo $?
0
$ [ 1 -gt 2 ]; echo $?
1
But if you use > inside of [[ .. ]] you are actually comparing strings and may be the wrong answer:
$ [[ 10 < 2 ]]; echo $?
0 # '0' means 'true' 10 < 2 only as strings
And you must use double [[ .. ]] to use > otherwise it is the redirection operator. (Thanks M. Nejat Aydin
...)

Crontab skip run once a week

I have a CRON expression that will run a given command every 8 hours, beginning at 00:00.
0 0,8,16 * * *
This will run a given commend 21 times a week, however, my goal is to skip one of these 21 runs on a weekly basis. What is the proper CRON expression to skip the first run on Sunday each week at 00:00 (in other words, an expression that will run 20 times per week)?
Make it 2 lines:
0 0,8,16 * * 0-5 At minute 0 past hour 0, 8, and 16 on every day-of-week from Sunday through Friday.
And
0 8,16 * * 6 At minute 0 past hour 8 and 16 on Saturday.
You can change the day and hour which you want to skip, but there is no way to do this in 1 line as far as I know.
Place this: [[ ( $( date +\%u ) -ne 0 ) && ( $( date +\%H:\%M) != "00:00" ) ]] && before your command.
If you don't want to use bash for your cron-job, this works with sh:
[ $( date +\%u ) -ne 0 ] && [ $( date +\%H:\%M) != "00:00" ] &&

How to schedule the job in cron which will run every month of 8th business day

I want to schedule a job which will run 8th business day of every month. How can i achieve it.
Format :
30 1 * 1-12 1 [Command]
You can try running this as a daily cron this:
#!/bin/bash
if [ -f ./ranThisMonth ]; then
if [ "$(date +%d -gt 10)" ]; then
rm ./ranThisMonth.tmp
fi
else
echo "Running now!"
if [[ "$(date +%u)" -lt 5 && "$(date +%d)" -ge 8 ]]; then
# Your commands here
touch ./ranThisMonth.tmp
fi
fi
if [ -f ./ranThisMonth ]; then checks whether it ran the current month
if [ "$(date +%d -gt 10)" ]; then in case its past the 10th resets it
if [[ "$(date +%u)" -lt 5 && "$(date +%d)" -ge 8 ]]; then if weekday (businessday) and past the 8th

How to generate sequential dates/times in a shell script?

I would like to download a bunch of data sets from 1981 to 2000 (20 years). Those are in every 10 minutes. I was trying to write a script which will call all times and download the data. But I am unable to complete it. I can't check the leap years and days in each month. My script is:
#!/bin/sh
for yr in {1981..2000};do
for mm in 01 02 03 04 05 06 07 08 09 10 11 12;do
for dd in {1..31};do
if [[ $dd -le 9 ]];then nn=0$dd;else nn=$dd;fi
for tt in 00 10 20 30 40 50; do
echo wget www.xyz.com/$yy/$mm/$nn/$tt.txt
done;
done;
done;
done
How can I fix the problems of leap years, and days in the month generally?
You seem to have left out the hours.
Assuming you have GNU date, you can deal with it by using the date calculations. Do you have to worry about switches between winter and summer (standard and daylight saving) time? If so, there'll be some entertainment to be had with gaps of an hour in the spring and a period in the fall when the raw date/time values repeat.
$ /opt/gnu/bin/date -d '1981-01-01 00:00:00' +'%s %Y-%m-%d %H:%M:%S'
347184000 1981-01-01 00:00:00
$ /opt/gnu/bin/date -d '2000-12-31 23:50:00' +'%s %Y-%m-%d %H:%M:%S'
978335400 2000-12-31 23:50:00
$
That gives you start and end times in Unix timestamp notation (and in the US/Pacific time zone — adjust to suit your needs). You could then use a loop such as:
now=347184000
end=978335400
while [ "$now" -le "$end" ]
do
url=$(date -d "#$now" +'www.example.com/%y/%m/%d/%H/%M.txt')
echo wget "$url"
now=$(($now + 600))
done
There are multiple ways of writing that. I've assumed that there's a directory of hourly files, and within that the 10-minute files, but you can tweak the format to suit your requirements. The use of # in the -d is crucial.
You might prefer to use a scripting language such as Perl or Python instead of repeatedly invoking date as shown.
Note that you have a vast number of files to collect. With about 31 million seconds per year, and 600 seconds per 10 minute interval, you're looking at over 50,000 files per year for 20 years, or 1 million files in total. The target (victim) web site might not be happy with you running that flat out. You'd probably need to pace the retrieval operations — check their terms and conditions.
This is how it can be (please note that this leap year calculation is good until 2100 only):
#!/bin/sh
for yr in {1981..2000};do
for mm in 1 2 3 4 5 6 7 8 9 10 11 12;do
for dd in {1..31};do
if [[ $dd -eq 31 ]] && ( [[ $mm -eq 4 ]] || [[ $mm -eq 6 ]] || [[ $mm -eq 9 ]] || [[ $mm -eq 11 ]] )
then
continue
elif ( [[ $dd -gt 28 ]] && [[ $mm -eq 2 ]] && [[ $(( $yr % 4 )) -ne 0 ]] ) || ([[ $dd -gt 29 ]] && [[ $mm -eq 2 ]] )
then
continue
fi
if [[ $mm -le 9 ]];then mon=0$mm;else mon=$mm;fi
if [[ $dd -le 9 ]];then nn=0$dd;else nn=$dd;fi
for tt in 00 10 20 30 40 50; do
echo wget www.xyz.com/$yy/$mon/$nn/$tt.txt
done;
done;
done;
done
I would use something to figure out the leap years etc for me ie date. The following might give a hint on how to do this.
They way you're using wget means it's going to create a bunch of files with
"10.txt.1"
"10.txt.2"
"10.txt.3"
"10.txt.4"
"10.txt.5"
This might be fine but if you want to put these in a directory on their own or to name the file as something else
#!/bin/bash
#Jan 01 1980
COUNTER=347155200
while [ $COUNTER -lt 978263999 ]; do
year=`date -r $COUNTER +"%y"`;
month=`date -r $COUNTER +"%m"`;
day=`date -r $COUNTER +"%d"`;
hour=`date -r $COUNTER +"%H"`;
min=`date -r $COUNTER +"%M"`;
let COUNTER=COUNTER+600
url="www.xyz.com/$year/$month/$day/$hour/$min.txt";
dir="$year/$month/$day/$hour";
file="$year/$month/$day/$hour/$min.txt"
mkdir -p $dir;
wget "$url" $file;
#Post process files here...
done

Set Cron Job for 1st working day of every month in Shell Scripting

I'm new to scripting language, can anyone please explain how to set the cron job for 1st working day?
You can use the following,
#monthly
Run once a month at the morning of the first day of the month.
0 0 1 * * /home/scripts/your_script_file.sh
3rd Edit:
This will run your job at morning say 10 AM on the first weekday of the month:
# First weekday of the month
# Monday - Friday
00 10 1-3 * * [ "$(date '+\%a')" == "Mon" ] && /home/scripts/your_script_file.sh
00 10 1 * * [ "$(date '+\%a')" == "Tue" ] && /home/scripts/your_script_file.sh
00 10 1 * * [ "$(date '+\%a')" == "Wed" ] && /home/scripts/your_script_file.sh
00 10 1 * * [ "$(date '+\%a')" == "Thu" ] && /home/scripts/your_script_file.sh
00 10 1 * * [ "$(date '+\%a')" == "Fri" ] && /home/scripts/your_script_file.sh
First, run the date command:
$ date '+%x'
> 12/29/2014
%x tells date to display today's date in the format of the current locale. Using that exact same format, put a list of holidays in a file called holidays. For example:
$ cat holidays
> 01/01/2015
> 07/04/2015
Next, create the following shell script:
#!/bin/sh
dom=$(date '+%d') # 01-31, day of month
year=$(date '+%Y') # four-digit year
month=$(date '+%m') # two-digit month
nworkdays=0
for d in $(seq 1 $dom)
do
today=$(date -d "$year-$month-$d" '+%x') # locale's date representation (e.g. 12/31/99)
dow=$(date -d "$year-$month-$d" '+%u') # day of week: 1-7 with 1=Monday, 7=Sunday
if [ "$dow" -le 5 ] && grep -vq "$today" /path/holidays
then
workday=Yes
nworkdays=$((nworkdays+1))
else
workday=
fi
done
[ "$workday" ] && [ "$nworkdays" -eq 1 ] && /path/command
Solution I have figured out:
0 9 1-3 * * [[ $(date +\%u) -lt 6 && (( $(date +\%d) -eq 1 || $(date +\%u) -eq 1 )) ]] && /home/scripts/your_script_file.sh
This should work:
59 6 1W * ?
Starts at AM6:59 every month at first Weekday.
a simple one run the scripte at 08:00 every first of the month for workdays Mon to Fri
00 8 1 * 1-5 /path/to/your_script_file.sh

Resources