0

i am swithcing my vps servers from centos to ubuntu. Because of the community (jeej my first question to that community).

I have cronjobs running perfectly on my centos vps like this:

01 22 * * * source /home/crawler2/env/bin/activate && cd /home/crawler2/project_spiderrooy && scrapy crawl spiderrooy > /home/crawler2/logs/spiderrooy_log_$(date '+\%Y-\%m-\%d').txt 2>&1

Tried that litterly on my ubuntu vps but that didn't work. Find a snippet online (on here somewhere that bash and dash work different so tried this:

01 22 * * * "$(command -v bash)" 'source /home/crawler1/env/bin/activate && cd /home/crawler1/project_spiderrooy && scrapy crawl spiderrooy > /home/crawler1/online/flask/static/logs/spiderrooy_log_$(date '+\%Y-\%m-\%d').txt 2>&1'

also doesn't work, tried it without writing the log and still doesn't work. The commands manually do work.

sudo grep CRON /var/log/syslog:

Jan 13 12:11:01 crawler2 CRON[2906]: (crawler2) CMD (-v bash)"  'source /home/crawler2/env/bin/activate && cd /home/crawler2/project_spiderahridderkerk && scrapy crawl spiderahridderkerk')
Jan 13 12:11:01 crawler2 CRON[2905]: (CRON) info (No MTA installed, discarding output)

With al my variations i never get the log file written, or the command executed, even without the log write of logwrite without the date.

The question, how do i run this centos cron in ubuntu, with the logwrite date, and how do i stop No MTA installed crap?

Thanks.

1
  • sourceis a bashism - the POSIX equivalent is . Jan 13, 2018 at 11:54

2 Answers 2

1

The underlying issue is that source is a Bashism - which is a problem in Ubuntu because the default shell for cron is /bin/sh - and that resolves to the dash shell.

The best way to handle that depends on a number of factors IMHO. The fix that you found elsewhere using command -v bash to run your command explicitly with the (fully qualified) bash shell is one option (although as noted in heemayl's answer, you missed the -c before the command string; based on the syslog entry

Jan 13 12:11:01 crawler2 CRON[2906]: (crawler2) CMD (-v bash)"  'source /home/crawler2/env/bin/activate && cd /home/crawler2/project_spiderahridderkerk && scrapy crawl spiderahridderkerk')

it actually looks more like your crontab entry was

01 22 * * * "($command -v bash)" source /home/crawler1/env/bin/activate && cd /home/crawler1/project_spiderrooy && scrapy crawl spiderrooy > /home/crawler1/online/flask/static/logs/spiderrooy_log_$(date '+\%Y-\%m-\%d').txt 2>&1'

such that ($command -v bash) expanded to ( -v bash) which attempted to execute -v bash in a subshell as well, rather than running command -v bash inside a command substitution).

In practice, it's unlikely (given cron's rather restricted default argument) that plain bash is going to resolve to anything different from $(command -v bash), so IMHO plain bash -c '. . .' or /bin/bash -c '. . .' would also be acceptable.

In comments, you noted your own solution was to add SHELL=/bin/bash - personally I have no problem with that: if you are concerned about the overhead of bash versus dash you can always limit the scope to a particular entry or group of entries e.g.

# default shell
*/3 * * * * /bin/echo "Job 1 run with \$SHELL=$SHELL" >> $HOME/crontab.log

SHELL=/bin/bash
*/5 * * * * /bin/echo "Job 2 run with \$SHELL=$SHELL" >> $HOME/crontab.log

SHELL=/bin/sh
*/7 * * * * /bin/echo "Job 3 run with \$SHELL=$SHELL" >> $HOME/crontab.log

results in

$ tail -f ~/crontab.log
Job 1 run with $SHELL=/bin/sh
Job 3 run with $SHELL=/bin/sh
Job 2 run with $SHELL=/bin/bash
Job 1 run with $SHELL=/bin/sh
Job 1 run with $SHELL=/bin/sh
Job 2 run with $SHELL=/bin/bash
Job 3 run with $SHELL=/bin/sh

Finally, if /home/crawler1/env/bin/activate is in fact a POSIX script (or can be made so relatively easily) and the remaining commands in your job are either binary executables or scripts with their own valid shebang lines, then you could simply change the source command to its POSIX-equivalent . such that everything runs in the default dash shell.

0
0

You're supposed to run whatever after $(command -v bash) as a bash command (bash -c ...), otherwise the whole thing would be treated as file(s) to be interpreted by bash.

Do:

"$(command -v bash)" -c 'source ...'

So, in crontab:

01 22 * * * "$(command -v bash)" -c 'source ...'
3
  • got it working now with stackoverflow.com/a/7031758/9108711 , SHELL=/bin/bash above the cronjob, is that a good way to handle this?
    – userRR
    Jan 13, 2018 at 11:52
  • @user9108711 No, it is not. Ubuntu defaults to sh (dash) for many reasons, including speed. While setting SHELL as bash wouldn't break anything POSIX but i would recommend keeping things as-is. Also, try the method I've provided, it should work.
    – heemayl
    Jan 13, 2018 at 11:56
  • 1
    Thanks, working! Great community and thank you for your fast response!
    – userRR
    Jan 13, 2018 at 12:07

You must log in to answer this question.

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