I have the following cron job setup on Debian 12:
/etc/cron.d/jonathan-test
:
SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin * * * * * jonathan /home/jonathan/test1.sh >> /home/jonathan/test.log 2>&1
/home/jonathan/test1.sh
:
#!/usr/bin/env bash export PATH="/home/jonathan/mytestdir:${PATH}" echo "test1.sh -> PATH=${PATH}" export PAAATH="this_is_a_test" echo "test1.sh -> PAAATH=${PAAATH}" exec "${HOME}/test2.sh"
/home/jonathan/test2.sh
:
#!/usr/bin/env bash echo "test2.sh -> PATH=${PATH}" echo "test2.sh -> PAAATH=${PAAATH}"
When it runs, it writes the following to /home/jonathan/test.log
:
test1.sh -> PATH=/home/jonathan/mytestdir:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin test1.sh -> PAAATH=this_is_a_test test2.sh -> PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin test2.sh -> PAAATH=this_is_a_test
As you can see, the $PATH
variable is not preserved by exec
.
This is a contrived, simplified example of my actual problem, which is with running pyenv from a cron job. If I change my cron.d
file to this:
SHELL=/bin/bash PYENV_ROOT=/opt/pyenv PATH=/opt/pyenv/shims:/opt/pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin * * * * * jonathan python --version >> /home/jonathan/test.log 2>&1
Then I get this written to the output file:
/opt/pyenv/libexec/pyenv-exec: line 24: pyenv-version-name: command not found
It correctly executes /opt/pyenv/shims/python
. That's just a bash script that runs pyenv exec python --version
. It correctly executes /opt/pyenv/bin/pyenv
, which is a symlink to /opt/pyenv/libexec/pyenv
, which is a bash script that modifies $PATH
to include /opt/pyenv/libexec
(and yes, it does export it!) and executes /opt/pyenv/libexec/pyenv-exec
, which is another bash script that tries to do PYENV_VERSION="$(pyenv-version-name)"
on line 24 which results in the error above, because /opt/pyenv/libexec
isn't in $PATH
. I've narrowed it down to the simplified example above. The exact same pyenv
setup with only environment variables and without the shell integration works just fine when not run from cron.
FYI, there's no sudo
anywhere in this, and I can reproduce it as other users too. So it doesn't seem to be related to secure_path
in /etc/sudoers
.
exec /usr/bin/env bash -x ~/test2.sh
. Maybe it reads somebashrc
file. Depending on how it's configured at build time, bash will read the bashrc when not interactive under some conditions, and some of those conditions involve$SHLVL
whichexec
here would have an influence on.$BASH_ENV
set to a file that was constantly resetting my$PATH
. I answered my own question below.