10

I'm setting up a docker container which requires a cronjob to do a backup using awscli.

I'm having a problem with the cron job being able to access the environment variables of the docker container. As I work around on startup I print all environment variables to a file printenv > /env.

When I try to use source from the cron job (I have tried both directly in crontab and in a script called by crontab) it doesn't seem to work.

I made a simplified version of my project to demonstrate the issue (including rsyslog for logging):

Dockerfile:

FROM debian:jessie

# Install aws and cron
RUN apt-get -yqq update
RUN apt-get install -yqq awscli cron rsyslog

# Create cron job
ADD crontab /etc/cron.d/hello-cron
RUN chmod 0644 /etc/cron.d/hello-cron

# Output environment variables to file
# Then start cron and watch log
CMD printenv > /env && cron && service rsyslog start && tail -F /var/log/*

crontab:

# Every 3 minutes try to source /env and run `aws s3 ls`.
*/3 * * * * root /usr/bin/env bash & source /env & aws s3 ls >> /test 2>&1

When I start the container I can see /env was created with my variables but it never gets sourced.

13
  • What are you doing? Do you have a file in your root directory named source? I'm pretty sure it should just be source and not /source
    – jesse_b
    Oct 14, 2017 at 13:44
  • Also do you know you are creating a file in your root directory named env and not using the actual env command?
    – jesse_b
    Oct 14, 2017 at 13:47
  • @Jesse_b sorry typo fixed. Oct 14, 2017 at 13:48
  • @Jesse_b Cron doesn't have access to my environment variables so I'm outputting them to a file on startup and sourcing them in the cronjob. Oct 14, 2017 at 13:49
  • 1
    @Jesse_b creating? I assumed there's a file called /env that has the environment variables that need to be sourced. Is that wrong Philip?
    – terdon
    Oct 14, 2017 at 13:49

2 Answers 2

14

First of all, the command's (well, shell builtin's) name is source. Unless you have written a script called source and put it in /, you want source and not /source.

The next issue is that cron usually uses whatever you have as /bin/sh and source is a bashism (or other such more complex shells). The portable, POSIX-compliant command for sourcing a file is .. So, try that instead of source:

*/3 * * * * root /usr/bin/env bash & . /env & aws s3 ls >> /test 2>&1

Also, I don't quite understand what that is supposed to be doing. What's the point of starting a bash session and sending it to the background? If you want to use bash to run the subsequent commands, you'd need:

*/3 * * * * root /usr/bin/env bash -c '. /env && aws s3 ls' >> /test 2>&1

I also changed the & to && since sourcing in the background is pointless as far as I can see.

7
  • I tried your original and suggestion and it didn't work. I'm going to re-build with your update and see if that works. Oct 14, 2017 at 13:53
  • @PhilipKirkbride if you mean the first one with root /usr/bin/env bash &, then that won't work, no. You're just sending a bash instance to the background. If the second one also fails, please explain exactly how it fails since "doesn't work" isn't very informative.
    – terdon
    Oct 14, 2017 at 13:54
  • @PhilipKirkbride if && breaks, that means the source failed yes. Most likely because you're not using bash so you need to do .. But running . file & (sourcing in the background) will never work because backgrounded commands run in their own subshell, so the variables you sourced will only be available there. If you want to run the second command even if the first failed, use ;, but don't use & here.
    – terdon
    Oct 14, 2017 at 14:01
  • 1
    @PhilipKirkbride I know, but I wanted to explain why & will always be wrong here.
    – terdon
    Oct 14, 2017 at 14:03
  • 2
    @PhilipKirkbride they are set, but are they exported? That's a big difference. That you can see the variable when you echo it doesn't mean that child processes inherit it. Compare foo='bar'; bash -c 'echo $foo' and export foo='bar'; bash -c 'echo $foo' to see what I mean.
    – terdon
    Oct 14, 2017 at 14:21
1

You can use . since as terdon's answer already mentioned that cron uses /bin/sh by default and doesn't recognize source command sometimes.

I wanted to add one more thing: you can't source file and use that in second command, so something like this might not work:

* * * * * source ~/.bash_profile
* * * * * do some stuff with bash_variables

Because each line is session itself so sourced variables in first command will not be available in later commands. You would have to do something like this:

* * * * * source ~/.bash_variable && do some stuff with bash_variables
1
  • @chaos: Is it possible to source for all commands? eg . /path/env \n * * * * * $MYENV/cmd param1 param2 Aug 5, 2022 at 11:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .