7

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).

7
  • 2
    why would you want to know this? Commented Jan 18, 2010 at 15:18
  • 1
    For example I want to change the way it does the output. When running from terminal I want to use coloring via ANSI escape sequences but when running from terminal I want plain text in order to receive nice emails. Commented Jan 18, 2010 at 15:22
  • 3
    Then check the terminal, not for cron. Commented Jan 18, 2010 at 15:28
  • 2
    @digitalarbeiter: I think it's just an example. Maybe he wants something a bit more complex than that. Commented Jan 18, 2010 at 15:29
  • 2
    @Stefano: Yeah, but "Explicit is better than implicit". Check what you actually need, explicitly. Goes for TERM, goes for any other changes in behaviour. Commented Jan 18, 2010 at 15:42

6 Answers 6

25

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.

Sign up to request clarification or add additional context in comments.

2 Comments

+1 This would be the right thing to do if you want different output based on whether you're outputting to the 'screen' or not.
sys.stdout.isatty() is more straightforward than os.isatty(sys.stdout.fileno()).
9

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.

2 Comments

cron will run your crontab entry in a new shell, which would be the PPID of your Python script. You'll need to compare the PPID of the PPID.
This assumes that the parent (cron) directly spawned off the child without a shell or something else in between. Not always true.
6

Set an environment variable at the cron command invocation. That works even within a module, as you can just check os.getenv().

Comments

3

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')

1 Comment

This depends on environment variables that are not usually set in Windows. Better to use sys.stdout.isatty()
2

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.

2 Comments

yup but he does not want to do that.
The original post was specific that that is not what he wants.
0

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).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.