Crontab for 1st Saturday -3 days

Sometime ago someone presented a way to run a shell script on first Saturday of month and 3 days prior. The Crontab was: 03 08-17 * * 3-5 [ $(date -d "next Saturday" +\%d) -le 07 ] && /run/your/script

Seemed to work, but it doesn't. (date -d "next Saturday" +\%d) correctly returns the numeric value of next Saturday, but when testing if it's less or equal to 7 [ $(date -d "next Saturday" +\%d) -le 07 ].
When testing in bash shell, bash throws an error with the -le

Anyone can explain/point to why? and explain how to overcome?

Thanks

It would be helpful if you posted the actual message text, and the shell name and version (being aware that cron runs /bin/sh by default, unless you use the SHELL=bash line in the crontab to run a specific shell).

Some shells treat numbers with leading zeros as Octal values. So comparisons with days 08 and 09 would throw an error something like 08: invalid octal number.

Formatting the date output with '+%e' or '+%_d' may solve the issue, but again this depends on your Distro and command versions. Both work on my /bin/sh (which runs dash), and on my GNU bash, version 5.1.16(1).

If you only trip the script on 3 days (Wed, Thursday, Friday), it is not going to run on four consecutive days (Saturday and the previous three days). You need another specific rule for Saturday which does not invoke "next Saturday".

1 Like

I thought the same, but actually it does work in bash 5.1.16(1) with [ ] or test.
But not with [[ ]] or (( ))

bash$ [ 08 -le 09 ] && echo true
true

Agreed, but we don't know what shell the OP is using (and it is not necessarily his default shell anyway).

1 Like

Ok guys, here is more data. Shell is bash, the result from the date call is correct as next Saturday will be the 14th, but (14 the result ) it's being looked at/perceived as a function call

[root@NB4TV asterisk]# echo $0
/bin/bash
[root@NB4TV asterisk]# [$(date -d "next Saturday" +\%d) -le 07] && echo true
bash: [14: command not 

@axm1955 use markdown code tags when posting code/data samples.

[ $(date -d "next Saturday" +%d) -le 07 ] && echo true

There should be a space after [ and before ]

3 Likes

sry bout the markdown code tags, not obvious
So now the result from the date expression is no longer being perceived as a function, but it does not resolve to either true or false

[root@NB4TV asterisk]# [ $(date -d "next Saturday" +\%d) -le 07 ] && echo true
[root@NB4TV asterisk]# [ $(date -d "next Saturday" +\%d) -le 07 ] && echo false

here's the markdown cheat-sheet

$ [ $(date -d 'next Saturday' '+%d') -le 7 ] && echo true || echo false
false
1 Like

There are some flaws in your diagnostics.

(1) Your original script (from October 2023) can never run on a Saturday. You need a separate rule for the first Saturday in the month, because "next Saturday" will be later.

(2) Your shell at your current command line might well be Bash, but crontab does not know that. man -s 5 crontab says: "The entire command portion of the line, up to a newline or % character, will be executed by /bin/sh or by the shell specified in the SHELL variable of the crontab file." My crond runs /bin/dash, but others may run ksh88, ksh93, or plain Bourne shell.

(3) "It does not resolve to true or false". The result merely decides whether the echo runs or not. It could be echo Hello World for all the shell cares.

(4) You should use shellcheck on any script or command fragment. It checks for syntax issues more thoroughly than shell, and has better diagnostics. It is available online, and is also downloadable. It would have caught your syntax issue.

1 Like

I don't find a shell where [ ] or test treat a number with preceding 0 as octal.
What's your shell? What yields

ls -ilL /bin/sh /bin/bash

?

In date -d just "Saturday" includes "today's Saturday".
So the following includes the first Saturday of the month:

03  08-17  *  *  3-6 [ $(date -d "Saturday" +\%d) -le 07 ] && /run/your/script

Note that in crontab you need \% that the shell must turn into a % - an old crontab misfeature.

1 Like

I don't have the whole range of shells to test. But your ls -ilL is incomplete.

paul: ~ $ ls -ilL /bin/sh /bin/bash /bin/dash

1184162 -rwxr-xr-x 1 root root 1396520 Mar 14  2024 /bin/bash
1179909 -rwxr-xr-x 1 root root  125688 Mar 23  2022 /bin/dash
1179909 -rwxr-xr-x 1 root root  125688 Mar 23  2022 /bin/sh

So sh and dash have the same inode, which is explained by:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Nov 16 17:08 /bin/sh -> dash

and man -s 5 crontab clearly states that crond by default will run /bin/sh, and therefore dash on my distro (which was news to me).

I don't see or recall any specific case of a test or [ command which rejects 08 or 09 as a decimal number, although I am sure I encountered the issue at some time.

However, there are constructs in both bash and dash which show an issue with numbers that exceed their base character set.

paul: ~ $ bash
paul: ~ $ printf '%d\n' 09
bash: printf: 09: invalid octal number
0
paul: ~ $ printf '%d\n' 077
63
paul: ~ $ printf '%d\n' 078
bash: printf: 078: invalid octal number
7
paul: ~ $ echo $(( 6 + 07 ))
13
paul: ~ $ echo $(( 6 + 08 ))
bash: 6 + 08: value too great for base (error token is "08")
paul: ~ $ dash
$ printf '%d\n' 077
63
$ printf '%d\n' 078
dash: 2: printf: 078: not completely converted
7
$ echo $(( 6 + 07 ))
13
$ echo $(( 6 + 08 ))
dash: 4: arithmetic expression: expecting EOF: " 6 + 08 "
$ echo $(( 6 + 0xF ))
21
$ echo $(( 6 + 0xG ))
dash: 6: arithmetic expression: expecting EOF: " 6 + 0xG "
$ 

Let's get somethings straight to make the question flow:

Always post the entire and unchanged error message, not "an error" or some interpretation. That makes all readers know exactly the problem you're having.

Do you have an explicit crontab directive stating SHELL=bash? As @Paul_Pedant already pointed out, cron uses sh as default shell, unless you specifically set another one.

In fact, the shell tries to interpret (almost always) the first word as a command or shell builtin. [ is indeed a shell builtin.

type [
[ is a shell builtin

Since this part lacked the spaces @vgersh99 warned about, the first word was [14, and the shell tried to parse it as a command or builtin.

All that said, pls provide:

  1. Your current crontab line (after all fixes you tried)
  2. Any errors you get

Finally, pls follow hints from this answer, specially 1 and 4.

1 Like

Thank you all for your valuable input, mostly to madeingermany for the original crontab entry.

To answer in order all the "which shell" questions it is bash in archlinux

My problem was with lack of understanding on how the code was parsed and hence all my difficulty. Reason I posted was to get some guidance ......
Link to markdown sheet is not working, so I may post this reply incorrectly, but if anyone else out there searching can benefit by my learning here is the final working crontab line for archlinux bash cron

 28 08-17 * * 3-5 [ $(date -d 'next Saturday' '+%d') -le 07 ] && (source /usr/local/etc/allstar.env ; /usr/bin/nice -19  /usr/sbin/asterisk  -rx  'rpt playback 55373 /etc/asterisk/local/saturday_meeting_eoc' > /dev/null)