Python does not get environment variable when using cron.
Cameron Simpson
cs at zip.com.au
Mon Aug 18 01:11:59 EDT 2008
On 17Aug2008 21:25, John Nagle <nagle at animats.com> wrote:
> Stephen Cattaneo wrote:
>> I am attempting to execute an automated test (written in Python) via
>> cron. I have to check the HOSTNAME variable as part of the test, oddly
>> under cron the HOSTNAME environment variable is not in the os.environ
>> dictionary. I know that cron runs in a subshell that does not have all
>> of the normally set environment variables. HOSTNAME is not one of those
>> variables, it is set even in cron's subshell. Why doesn't python get
>> this variable? Is this a bug in python2.4?
Because $HOSTNAME is a bash specific variable, set by bash but NOT
EXPORTED! Like $0 and a bunch of other "private" variables, subprocesses
do not inherit this value. From "man bash":
Shell Variables
The following variables are set by the shell:
[...]
HOSTNAME
Automatically set to the name of the current host.
Note that "set" does not imply "exported". Only exported vairables are
seen by subprocesses.
> Cron doesn't normally use a shell at all. It just runs the
> requested program in a subprocess. So there's no shell involved,
> and you don't get a shell-type user environment.
This statement is false.
Cron hands _all_ jobs to a shell. From "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 % char-
acter, will be executed by /bin/sh or by the shell specified in the SHELL
variable of the cronfile.
That's from Vixie cron, but all UNIX crons hand the command part of the
cron line to a shell, usually /bin/sh.
You're probably confused by the fact that cron does not invoke "login" shells
(with their associated initialisation from /etc/profile and $HOME/.profile).
> If you have
> a crontab line like
> 10 3 * * * /usr/bin/python someprogram.py
> there's no shell.
Not so. A shell will be interpreting the string "/usr/bin/python
someprogram.py", mch as happens when you type this on the command line.
> You can try
> 10 3 * * * /bin/sh /usr/bin/python someprogram.py
> which will load a shell, which in turn will load Python.
Even more not so. The command "/bin/sh /usr/bin/python someprogram.py"
will attempt to parse the file "/usr/bin/python" as though it were a
shell script. That's almost certainly not what you wanted.
To do what you describe requires the line:
/bin/sh -c '/usr/bin/python someprogram.py'
which hands the command string "/usr/bin/python someprogram.py" to
/bin/sh for interpretation. Were you to do this as a cron line, the
string: "/bin/sh -c '/usr/bin/python someprogram.py'" would be handed
to /bin/sh for interpretation. That interpreter in turn then hands
"/usr/bin/python someprogram.py" to /bin/sh for interpretation.
A parent-child nested process listing (with some fake quoting tossed in
to show the strings) would look like this:
/bin/sh -c "/bin/sh -c '/usr/bin/python someprogram.py'"
/bin/sh -c '/usr/bin/python someprogram.py'
/usr/bin/python someprogram.py
i.e. three process alive.
> Or, in Python, you can use "socket.gethostname()", which will
> get you the host name used for networking purposes.
Or, on a cron line (after the time fields, omitted here):
HOSTNAME=`hostname`; export HOSTNAME; python someprogram.py
Cheers,
--
Cameron Simpson <cs at zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/
186,282 miles per second - Not just a good idea, It's the Law!
More information about the Python-list
mailing list