8

I have some commands, they are working under bash, but not as cronjob. To see, what cause the problem, i'm saving the output in a file, here my example:

51  *  *   *   *    source ~/.rvm/scripts/rvm >> stack.log 2>&1

The content of the log file is:

/bin/sh: 1: source: not found

That means, cron is using sh insead of bash. I've tried to change it in the /etc/crontab:

SHELL=/bin/bash

But this doesn't work. I've looked in the /etc/passwd and here i see, that the daemon is using sh as default shell. Both root and pi have bash as default shell.

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
pi:x:1000:1000:,,,:/home/pi:/bin/bash

What should i do to change the default shell for cron? I wouldn't set /bin/bash for the daemon user in /etc/passwd...imho this is not a good idea.

edit:

ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 30  2012 /bin/sh -> dash

here the content of the /etc/crontab:

# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
cupakob
  • 1,027
  • 3
  • 13
  • 17
  • 1
    Why do you want to source in crons environment? Simply running the ~/.rvm/scripts/rvm doesn't work? And you can have problems with using ~ in non-bash-environments. – macrojames Oct 10 '12 at 10:07

4 Answers4

4

Most such cases (where script works in shell but not in cron) are because of environment variables that are different in script. In many case the problems is PATH variable. You could use full paths to all executables you are running in script or modify PATH in first line of your script.

To trace such issues, you could start from dumping environment variables aviable to your script by using env command, like this: /usr/bin/env >/tmp/env.txt

Krzysztof Adamski
  • 9,615
  • 1
  • 37
  • 53
  • i don't have any environment variables in my script...and /bin/env doesn't exists. – cupakob Oct 10 '12 at 08:09
  • 2
    No, you always have some enviroment variables in each shell. One example is PATH which was already mentioned. Try /usr/bin/env instead. Or use which env to check what is your full path to env util. – Krzysztof Adamski Oct 10 '12 at 08:10
4

The shell used is dash; a POSIX-compliant shell, which is designed to be much smaller and more stable than bash.

One could argue that you should be writing cron jobs to be POSIX-compliant. Alternatively, try encapsulating your logic into a script and prepending the shebang

#!/usr/bin/env bash
Alex Chamberlain
  • 15,530
  • 14
  • 67
  • 113
3

Are you sure that sourcing your script into cron is absolutely what you want to do and, more importantly, necessary? I think that it's almost always a bad idea.

Moreover, when you're editing cron (as well as other tools that can be possibly launched by other users and/or other shells), try to take a step-by-step approach. For example, you can test your environment with something like this:

42  *  *   *   *    bash -c "echo home---$HOME---"   >> /tmp/cron-temp.log 2>&1
42  *  *   *   *    bash -c "echo shell---$SHELL---" >> /tmp/cron-temp.log 2>&1

or even:

42  *  *   *   *    bash -c "export"                 >> /tmp/cron-temp.log 2>&1

So you can have proof of your environment, etc.

To answer your question, I wouldn't change the shell for cron. I'd simply tell it to call bash and then let bash call your scripts.

Avio
  • 1,217
  • 2
  • 14
  • 25
  • the $SHELL was still 'sh' notwithstanding i have changed it in the /etc/crontab – cupakob Oct 10 '12 at 21:06
  • 1
    Yes, it's also the default in my cron. As I said, I wouldn't change it. Just call your script through bash with bash -c "yourscript" and everything should be fine (don't source your script, you probably don't need it!) – Avio Oct 10 '12 at 21:10
  • yes, this will work, but i want to know, why the default shell was not changed. – cupakob Oct 10 '12 at 21:30
3

So....i have two solutions for my problem:

  1. Wrapper script over the bash command, which i'm calling at the moment as cronjob. The problem here - for every cronjob i need one wrapper, and this is not the best sollution for me.

  2. I've tried to call a ruby script as cronjob. This doesnt work, so i thought, i need to call 'rvm use 1.9.3' and for that i need first to call 'source ~/.rvm/scripts/rvm'. And here was my mistake. In my bash instance i have path to ruby, but not as cron. After i fixed this, everything is working fine and i can execute my ruby scripts als cronjob.

Alex Chamberlain helped me a lot and give me the most important hint(s). Thanks a lot for the help!!!

cupakob
  • 1,027
  • 3
  • 13
  • 17