I would like to know how can I determine if a python script is executed from crontab?
I don't want a solution that will require adding a parameter because I want to be able to detect this even from an imported module (not the main script).
I would like to know how can I determine if a python script is executed from crontab?
I don't want a solution that will require adding a parameter because I want to be able to detect this even from an imported module (not the main script).
Not quite what you asked, but maybe what you want is sys.stdout.isatty(), which tells if stdout is connected to (roughly speaking) a terminal. It will be false if you pipe the output to a file or another process, or if the process is run from cron.
sys.stdout.isatty() is more straightforward than os.isatty(sys.stdout.fileno()).Check its PPID - the ID of its parent process. Compare that to the cron pid; If they are the same, it was invoked by the crontab.
This can be done by:
$ sudo ps -Af | grep cron | grep -v grep
root 6363 1 0 10:17 ? 00:00:00 /usr/sbin/cron
The PID of the cron process in this example is 6363. It is worth mentioning that the PPID of cron is 1 - the init process.
Now find out what is the PID of your python program:
$ sudo ps -Af | grep SorinSbarnea.py
adam 12992 6363 1 12:24 pts/2 00:04:21 /usr/bin/python SorinSbarnea.py
Its PID is 12992 and PPID is 6363, so it was indeed invoked by the cron process.
EDIT:
The cron process might not invoke your process directly. Hence, you'll have to traverse the PPIDs from your process upwards, till reaching PPID=1 or PPID=/usr/sbin/cron's PID. This can easily be done using a small shell or python script; just parse the output of ps:
$ cat /proc/12992/status
....
Pid: 12992
PPid: 7238
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
...
The next step would be checkig /proc/7238, and so forth. Again, This is really easy to implement using shell or python script.
Thanks, @digitalarbeiter and @Noufal Ibrahim for pointing it out in your comments.
The following shows how to detect whether the program has a terminal and whether it has a display. As a cron job, both will be returned as None.
#!/usr/bin/python
import os
term = os.getenv( "TERM" )
print( "term %s"%term )
display = os.getenv( "DISPLAY" )
print( "display %s"%display )
The output when run from a desktop terminal session will be similar to the following:
term xterm-256color
display :0
And when it is run as a cron job, the output will be:
term None
display None
You can test for the presence of either of these, like this
if term is None:
print( "no terminal" )
if display is None:
print( "no display" )
For one further example, the following selects an appropriate matplotlib backend when run from a cron job:
if os.getenv( "DISPLAY" ) is None:
print( "Using Agg" )
import matplotlib
matplotlib.use('Agg')
sys.stdout.isatty()An easier workaround would be to pass a flag to the script only from the crontab, like --crontab, and then just check for that flag.
If you want to detect this from an imported module, I would have the main program set a global variable in the module, which would output different things depending on the value of this global variable (and have the main program decide how to set the variable through a flag that you would use in your crontab). This is quite robust (comparing to studying PPIDs).