User Tools

Site Tools


cron

If you want to send us your comments, please do so. Thanks
More on comments


cron

cron mail filter: cron-deja-vu. It filters unwanted recurring cron e-mails,

incron: cron-like daemon which handles filesystem events. incron is an “inotify cron” system driven by filesystem events instead of time events.
Edit with incrontab -e

Main rule

Always put the code in a script
Start the script with

#! /bin/bash

Then call the script from cron. If you do not you can get something like

/bin/sh: 1: [[: not found

in the case you used an [[ statement for example

Use DISPLAY:0

DISPLAY=:0 needs to be added on a seperate line in the variables section, before the cron commands. This is needed for old Linux reasons whereby the audio is linked to the display. See Cron sechduling to play music using mpg123 issue:

For various reasons, audio playing is typically attached to where the display (X server)
is running on Linux. The cron process doesn't know about any display settings for the
system, so can't play audio unless you tell it how.

(This is one of the old and confusing bits about ‘the Unix way’ that I wish would go away
forever. How much sense does it make to have to do something about a display when you
want audio? None!)

manpages

man 8 cron
man 1 crontab
man 5 crontab
man 8 run-parts

Environment variables

VariableRemark
HOME=/home/userThis is an example
LOGNAMEMay NOT be changed
MAILTO=useruser to send the output e-mail to. user can also be a full e-mail address like something@somewhere.tld
PATH=/home/userThis is an example
SHELL=/bin/bashThe default shell is “/bin/sh”
DISPLAY=:0Define the display for GUI output and audio output. Or DISPLAY=:0.0
XAUTHORITY=/home/user/.XauthorityNeeded for DISPLAY
XDG_RUNTIME_DIR=“/run/user/1000”Needed for DISPLAY
LOCALESAll variables from the locales

Job definition

/etc/crontab

# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed

crontab -e

This is about the users own crontab. user-name is not needed

# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * command to be executed

More of the same

When a command has to be executed several times on a day, day of month, month, day of week use, example:

List3,6,7Execute at 3 and 6 and 7
Range5-9Execute at 5 and 6 and 7 and 8 and 9
Step3/5Execute at 3 and 8 and 13 and 18 and 23Does not work in Debian
Step*/20Execute at 20 and 40Does work in Debian

dow (day of the week)

0 or 7 Sun(day)
Use the day of the week number, the full day name or the three letter shortended version like in the sunday options example above or have a look in this table

0   Sun  SUN    Sunday
1   Mon  MON    Monday
2   Tue  TUE    Tuesday
3   Wed  WED    Wednesday
4   Thu  THU    Thursday
5   Fri  FRI    Friday
6   Sat  SAT    Saturday
7   Sun  SUN    Sunday

A reference: Crontab day of the week syntax

Other time indicators

@reboot
@hourly
@daily
@weekly
@monthly

Skipping @reboot jobs

When @reboot is used and cron is restarted via systemctl restart cron.service you can get

aug 08 09:37:24 Hostname cron[10663]: (CRON) INFO (Skipping @reboot jobs -- not system startup)

because it is not a (re)boot, cron is not started at (re)boot

Output to audio

This (when DISPLAY=:0 is added before all jobs) worked on Buster. Not on Bookworm anymore:

 43 * * * * mpg123 /home/user/someaudio.mp3 >> /dev/null 2>&1

Bookworm

On bookworm pipewire is used. Make sure cron has access to the pipewire user session
Turn this on via the pulseaudio support of pipewire via TCP
Copy the pulse.properties block from /usr/share/pipewire/pipewire-pulse.conf to ~/.config/pipewire/pipewire-pulse.conf.d/properties.conf and uncomment de tcp:4713 entry
Configure mpg123 to use the pulseaudio server on localhost

mpg123 http://localhost:4713 /home/user/audio.mp3

Output to GUI

Add to the cron envrironment variables (crontab -e)

DISPLAY=:0
#DISPLAY=:0.0
XAUTHORITY=/home/user/.Xauthority

Works for

/usr/bin/xmessage Helloxmessage
/usr/bin/notify-send Hello

Or do something like

/bin/bash -c 'DISPLAY=:0 /usr/bin/xmessage Hello'

This does not work

/bin/bash -c 'DISPLAY=:0 /usr/bin/notify-send Hello'

e-mail

MAILTO

When a script is ran from cron all echo output is send to the user via an e-mail
The e-mail address can be set with MAILTO=user, MAILTO=user@hostname or MAILTO=name@somedomain.tld
MAILTO=user@$HOSTNAME does not work
Put the MAILTO statement above the # m h dom mon dow command line

Output redirection to e-mail

Send output of a cron job to a specific user

7 * * * * somescript.sh | mail -s "Subject" name@e-mailprovider.com

Output redirection to a file

Send output to a file

7 * * * *  somescript 2>&1 >> $HOME/cron.log
7 * * * *  somescript >> $HOME/cron.log 2>&1

Do not send the output anywhere

7 * * * * somescript >/dev/null 2>&1

File locations

User cron

The crontab file is saved in /var/spool/cron/crontabs/username
To edit the crontab file run

crontab -e

System wide cron

Each entry also needs a username after the 5 time and date positions

/etc/crontab

General cron

/etc/cron.d

Fixed time files

/etc/cron.daily 
/etc/cron.weekly 
/etc/cron.monthly

cron options file

/etc/default/cron

systemd cron unit file

/etc/systemd/system/multi-user.target.wants/cron.service

init cron deamon file

/etc/init.d/cron

Separate cron log file

Recommended
As root do

  • touch /var/log/cron.log
  • chown root:syslog /var/log/cron.log
  • chmod 664 /var/log/cron.log
  • vi /etc/rsyslog.d/50-default.conf
    • Remove the # at the line starting with #cron.*
    • Save and close the file
  • systemctl restart rsyslog
  • systemctl status rsyslog
  • Read the log: less -S /var/log/cron.log

Limitations

  • Jobs can be missed on systems which are not on 24 hours a day. In that case use anacron. To run anacron jobs in user mode
    • This is not true. In fact anacron is useless if you need to run a job again, after a reboot, within 24 hours. In that case use a script and add its execution to crontab. See an example below
  • Under investigation: When the computer is started and presenting the login screen, no user is logged in, cron runs the cron jobs of all users including the root user on the computer
    • Beep sounds are not played when the user is not logged in.
      • Beep sounds are played when the user is logged in
  • When audio is playing the audio played via cron might not be heard. This depends on the sound card. Some examples:
    • Beep plays always from cron when the user is logged in
    • When a mp3 file is playing with mpg123 a mp3 file played with mpg123 from cron plays also
    • When a video is playing in a webbrowser a mp3 file played with mpg123 from cron does not play.
      • The mp3 file played with mpg123 from cron plays when the video in the webbrowser is paused, this is not always the case. Reason unknown, under investigation

Example script

#! /bin/bash
CONSTAT=0
export CONSTAT
 
if [[ $CONSTAT -eq 0 ]]; then
#if ! [[ -f /tmp/34con.txt ]]; then
        if [[ $(nmcli connection show --active | tail -n 1 | tr -s ' ' | cut -d ' ' -f 1) == enp3s0 ]]; then
                nmcli -p con up "78 netwerk enp3s0   78.34"
                # con is hetzelfde als connection
                echo "Networkmanager connection changed to 78.34"
        else
                echo "Networkmanager connection is already at 78.34"
        fi
CONSTAT=1
export CONSTAT
#       echo 34connection.sh has run on $(date) > /tmp/34con.txt
fi

32 / 64 bit computers

It seems that cron has different behaviour on an 32 bit Debian system and an 64 bit Debian system

/etc/cron.daily and alike

Also valid for /etc/cron.hourly/ and /etc/cron.weekly/ and /etc/cron.monthly/ and probably also for /etc/cron.d/

Scripts in these directories are not allowed to have an extension, a dot in the filename. If they do they will not get executed.

cli differences to cron

chown

This command has to be run as root
When run from a normal cron job it results in an error
If run as

sudo chown user:user folder/

it works if

user     ALL=(root:ALL) NOPASSWD:/bin/chown *\:* *

is added to the sudoers file. Do this as root with

visudo

echo

When using the -e option it only works fine in a script. Make sure to add #! /bin/bash at the first line of the script
When echo -e is used it is needed to do “\” expansion on the commandline and in scripts, not in cron
In cron -e is not needed, if used it will be displayed as literal -e. This works fine:

36,38 * * * * echo "Some test\t\t$(date)" >> $HOME/crontest.txt

The echo output in a script in the e-mail cron sends is the same for

echo -e "Some text"
echo -e "\033[01;46;37mSome text\033[00m"

date

date +'%s'
date "+%s"
echo -e "\nDone at $(date +'%s') which is at $(date +'%d-%b-%Y %H:%M UTC')"

$USER

cron does not know about the user. So the $USER variable is empty. Demonstration: Add to cron:

* * * * * echo -e "$(date)\tuser: $USER" >> $HOME/crontest.txt

Check crontest.txt after a few minutes
Do not forget to turn this cronjob off after testing :-)

Getting the username of the user on whose behave cron has executed the job can be achieved by using

USERcron=$(whoami) # The user who ran the script or on whose behave cron has ran

or with

USERcron=$(echo $HOME | cut -d / -f 3)

This works for both root and a normal user
Make sure to define user in every file called by an other file

Also

USERcron=$(id -u)

holds the user in cron. Only it is the numeric representation root being 0 and the first added user mostly 1000

Check if a script is run from cron or started by a user

Use $USER

Proof of concept

#! /bin/bash
USERcron=$(whoami) # The user who ran the script or on whose behave cron has ran.
                      # This works for both root and a normal user, interactive or ran from cron.
echo "user_whoami: $user_whoami"
 
echo USER: $USER # When ran interactive $USER has a value. When ran from cron $USER is empty
 
if [[ -z $USER ]]; then # USER is an empty string so ran from cron
  interactive=1		#No, the script is initiated by cron
  echo -e "User is: $USER\tinteractive is: $interactive"
  echo -e "Ran from Cron"
else	# Double check
  if [[ -n $USER ]]; then # USER is a normal user. The sting is not empty
    interactive=0	#Yes, the script is initiated by the user
		echo -e "User is: $USER\tinteractive is: $interactive"
    echo -e "Initiated by the user, not ran from Cron"
  else
    echo Strange error when determining who ran this script
  fi
fi

Use a variable

This does not work if you want to read calledfromcron in somescript.sh the variable unkown, its value is empty. nice -n 19 is just there for the demo

  cron entry: * 20 23 6 2 export CALLEDFROMCRON=1; nice -n 19 echo Hallo from cron. calledfromcron is: $calledfromcron; $HOME/somescript.sh; export CALLEDFROMCRON=0

This works. The sleep 20 command is added so /tmp/calledfromcron.txt is removed when $HOME/somescript.sh has probably finished execution. Not a perfect solution but it might work in certain cases

  cron entry: * 21 23 6 2 echo "calledfromcron" > /tmp/calledfromcron.txt; $HOME/somescript.sh; sleep 20; rm -f /tmp/calledfromcron.txt
  cron entry: * 21 23 6 2 touch /tmp/calledfromcron.txt; $HOME/somescript.sh; sleep 20; rm -f /tmp/calledfromcron.txt

Use ps

Thanks to Sebastiaan
The Z is added to avoid comparison of empty strings which will give an error
The “ are added to avoid misinterpretation of spaces

#!/bin/bash
if [ "Z$(ps o comm="" -p $(ps o ppid="" -p $$))" == "Zcron" -o \
      "Z$(ps o comm="" -p $(ps o ppid="" -p $(ps o ppid="" -p $$)))" == "Zcron" ]
then
     echo "Called from cron on $(date)" >> ~/test.txt
else
     echo "Not called from cron on $(date)" >> ~/test.txt
fi

This does not work

Just for reference:
Check if $- includes the i flag. The i is set for interactive shells
If cron is running the i is not present. But also when this is implemented in a script, that is ran from the command line, it is in non interactive mode so the i flag is not set also
You can from the commandline and as a command in cron

  echo Flags: $-
  if [[ $- == *i* ]]; then echo i flag is present; fi

You can run this script form the commandline and with cron

#! /bin/bash
 
case "$-" in
    *i*)
        INTERCACTIVE=1
        ;;
    *)
        INTERCACTIVE=0
        ;;
esac
 
if [[ $INTERCACTIVE -eq 0 ]]; then
    touch $HOME/not_interactive.txt
fi
 
if [[ $INTERCACTIVE -eq 1 ]]; then
    echo "Interactive"
fi

Errors

bad minute

After saving and closing the file opened with crontab -e

$ crontab -e
crontab: installing new crontab
"/tmp/crontab.abcde/crontab":20: bad minute
errors in crontab file, can't install.
Do you want to retry the same edit? (y/n) y
crontab: installing new crontab
$

20 is the linenumber the error is found on
This happenes when you want to split long lines with a \
Extra spaces to line out the code of the command are allowed

redirection unexpected

/bin/sh: 1: Syntax error: redirection unexpected

Solution: write a script and execute it with cron

MP3 file does not play

Under investigation:
See also limitations Example of the cronjob

0 * * * * mpg123 /home/user/audiofile.mp3

The mp3 file does not always play. Sometimes it plays sometimes it does not. After a while it did not play at all anymore.

It has heard being played while an other mp3 file is pause and while an other mp3 file is played
Everything works fine after pausing a Rumble video in Firefox. Youtube videos might cause the mp3 file not to play.

Ran the script containing

!# /bin/bash
/usr/bin/mpg123 /home/user/someaudio.mp3 >> /home/user/someaudio.log 2>&1

from cron
This resulted in (cat /home/user/someaudio.log):

High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3
version 1.25.10; written and copyright by Michael Hipp and others
free software (LGPL) without any warranty but with best wishes
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Segmentation fault

When the script is ran in a terminal it runs fine, the mp3 file is played

Solution: The commandline should be one of these two:

DISPLAY=:0.0 mpg123 /home/user/someaudio.mp3
DISPLAY=:0.0 /usr/bin/mpg123 /home/user/someaudio.mp3

Crontabs reboot only works for root
Cron settings aid
Ubuntu cron howto
Cronitor: a cron monitor


Main subjects on this wiki: Linux, Debian, HTML, Microcontrollers, Privacy

RSS
Disclaimer
Privacy statement
Bugs statement
Cookies
Copyright © : 2014 - 2024 Webevaluation.nl and the authors
Changes reserved.

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
cron.txt · Last modified: 28-09-2023 09:59 by wim