The main differences between running a command from cron and running on the command line are:
- cron is probably using a different shell (generally
/bin/sh
);
- cron is definitely running in a small environment (which ones depends on the cron implementation, so check the
cron(8)
or crontab(5)
man page; generally there's just HOME
, perhaps SHELL
, perhaps LOGNAME
, perhaps USER
, and a small PATH
);
- cron treats the
%
character specially (it is turned into a newline);
- cron jobs run without a terminal or graphical environment.
The following invocation will run the shell snippet pretty much as if it was invoked from cron. I assume the snippet doesn't contain the characters '
or %
.
env - HOME="$HOME" USER="$USER" PATH=/usr/bin:/bin /bin/sh -c 'shell snippet' </dev/null >job.log 2>&1
See also executing a sh script from the cron, which might help solve your problem.
For Q1 & Q2, see here. Q3 is answered in the discussion of your other three questions below.
WRT $BASH_ENV
, from man bash
:
When bash is started non-interactively, to run a shell script, for
example, it looks for the variable
BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as
the name of a file to read and execute.
So this could be a .profile
type script. As to where or who set it, this depends on context -- generally it is not set, but it could have been by any ancestor of the current process. cron
does not seem to make any special use of this, and AFAIK neither does init.
Does it mean that cron itself runs in Bash?
If by "in" you mean, is started from a shell, then this depends on the init system -- e.g., SysV executes shell scripts for services, so those services are always started via a shell.
But if by "in" you mean, "Is it thus a child of a shell process?", no. Like other daemons it runs as the leader of its own process group and its parent process is the init process (pid 1).
The consequences for cron
's environment are probably immaterial, however. For more about the environment of start-up services, see the answer linked above regarding Q1 & Q2. WRT to cron specifically, according to man 5 crontab
it also sets some environment variables that are inherited by any process it starts ($LOGNAME
, $HOME
, and $SHELL
).
The commands specified in crontab are interpreted in Bash?
They're interpreted with sh
or $SHELL
; again from man 5 crontab
:
The entire command portion
of the line, up to a newline or a "%" character, will be executed by /bin/sh or by the shell specified in the SHELL variable of the cronfile. A "%" character in the command, unless escaped with a
backslash (), will be changed into newline characters, and all data after the first % will be sent
to the command as standard input.
The emphasized part anwsers Q3.
The scripts that do not have shebangs in them, are run using $SHELL
Executable scripts with or without shebangs are opened by $SHELL
(or sh
). The difference is, those with a shebang will then be handed to the appropriate interpreter (#!/bin/sh
being another instance of the shell), whereas executable scripts (ones with the executable bit set that are reference as executables) without a shebang will simply fail, just as they would when run from the command line (unless you run them sh script.sh
).
Best Answer
If you want all the bash scripts in your crontab to load
BASH_ENV
, set it at the crontab level.If you want to set
BASH_ENV
only for a particular entry, set it there. ThenBASH_ENV
won't be set for the code listed in the crontab itself, but it's a bad idea to put anything complex there anyway.If you want a particular script to always load some configuration file, load it directly from within the script.