7

I have written various scripts to launch Java server applications, which are typically run for 24 hours before being shut down (by invoking the same script with a different parameter).

The script relies on environment variables defined in a file: ~/<user>.env, which I source from .bashrc.

This works fine when invoking the script from the command line but if I want to add the script as a crontab entry I run into the problem where .bashrc isn't read.

My question: What is the best practice approach for solving this problem? I realise I could define a crontab entry such as:

* * * * 1-5 /usr/bin/bash -c '. /home/myuser/myuser.env && /home/myuser/scripts/myscript.sh'

... but this seems plain ugly. Alternatively I could source myuser.env at the beginning of every script, but this would become a nightmare to maintain.

Any help appreciated.

Adamski
  • 281
  • 1
  • 2
  • 7

6 Answers6

11

I usually address this with a short cron wrapper script:

#!/bin/bash
[ -r $HOME/.bashrc ] && . $HOME/.bashrc
[ -r $HOME/.profile ] && . $HOME/.profile
exec "$@"

Then just prefix the command in crontab with your wrapper:

* * * * 1-5 ~/scripts/cron-wrapper ~/scripts/myscript.sh
* * * * 1-5 ~/scripts/cron-wrapper ~/scripts/myotherscript.sh

Some versions of cron allow you to set variables directly in crontab. Unfortunately, I don't get to use those at work.

pra
  • 622
  • 1
  • 5
  • 13
11

I actually discovered a fairly elegant solution by adding the '-l' (--login) flag to my bash command, which causes it to source all login files, including .bashrc. Hence my crontab command is simply:

* * * * 1-5 /usr/bin/bash -lc '/mnt/group/core/deploy/scripts/test.sh' > /dev/null 2>&1
Adamski
  • 281
  • 1
  • 2
  • 7
  • In this case (and really any solution to this issue), make sure you're not putting interactive-only things in your profile or bashrc without at least testing for the presence of a tty. – pra Sep 03 '21 at 03:30
3

An alternative (although not necessarily better) option would be to add these into root's crontab, and have the entry use su with a dash to become the user in question. The environment variables would then be pulled in automatically via the user's default shell environment in ~/.bashrc, or the like. eg:

* * * * 1-5 su - scriptuser '/home/myuser/scripts/myscript.sh' This would run the job as scriptuser, with all the environment variables of a proper login. The downside is that scriptuser himself couldn't set this job up -- it would require root privileges to do that.

Christopher Karel
  • 6,442
  • 1
  • 26
  • 34
1

cron-wrapper solution worked for me with one modification, I needed to replace the $HOME with the absolute path to the user home folder, in this case it was:

#!/bin/bash
[ -r /root/.bashrc ] && . /root/.bashrc
[ -r /root/.profile ] && . /root/.profile
exec "$@"
Datageek
  • 161
  • 5
0

The only other thing I can think of would be based on:

bash -i --rcfile 'init' -c 'script'

which is probably less attractive.

Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
  • I actually tried this and it doesn't work. According to the GNU bash manual, --rcfile "Execute commands from filename (instead of ~/.bashrc) in an interactive shell.", and as I'm not running an interactive shell I presume this is why it's failing. – Adamski Feb 25 '10 at 10:56
  • @Adamski: The `-i` makes the shell think it's interactive. – Dennis Williamson Feb 25 '10 at 13:38
0

Recent versions of cron allow you to set arbitrary environment variables before running jobs. So you could add this to your crontab:

CRON=1

Then in your .bash_login do something like this:

[ -n "$CRON" ] && . .bashrc

digdug
  • 1