我正在将我的 vps 服务器从 centos 切换到 ubuntu。因为社区(jeej,这是我向该社区提出的第一个问题)。
我的 cronjobs 在我的 centos vps 上完美运行,如下所示:
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
在我的 ubuntu vps 上试了几次,但没用。在网上找到一个代码片段(这里某处 bash 和 dash 的工作方式不同,所以尝试了这个:
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'
也不起作用,尝试过不写日志,但仍然不起作用。手动命令确实有效。
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)
使用我的所有变体,我都无法写入日志文件,也无法执行命令,即使没有不带日期的 logwrite 日志写入也是如此。
问题是,我如何在 ubuntu 中运行这个 centos cron,并使用 logwrite 日期,以及如何停止未安装 MTA 的垃圾?
谢谢。
答案1
根本问题source
是巴什主义- 这在 Ubuntu 中是一个问题,因为 的默认 shellcron
是/bin/sh
- 并且解析为dash
shell。
处理这个问题的最佳方法取决于许多因素。你在其他地方找到的修复方法是使用command -v bash
(完全合格的)bash shell 显式运行命令,这是一种选择(尽管如heemayl 的回答,你错过了-c
命令字符串之前的;基于 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')
它实际上看起来更像你的 crontab 条目
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'
扩展($command -v bash)
到也( -v bash)
试图-v bash
在子shell中执行,而不是command -v bash
在命令替换中运行)。
实际上,plain 不太可能(考虑到 cron 相当受限制的默认参数)bash
解析为不同于 的任何内容$(command -v bash)
,因此恕我直言,plainbash -c '. . .'
或/bin/bash -c '. . .'
也是可以接受的。
在评论中,你指出你自己的解决方案是添加SHELL=/bin/bash
- 我个人对此没有问题:如果你担心 bash 与 dash 的开销,你可以始终将范围限制为特定条目或条目组,例如
# 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
结果是
$ 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
最后,如果/home/crawler1/env/bin/activate
实际上是一个 POSIX 脚本(或者可以相对轻松地制作成 POSIX 脚本),并且作业中的其余命令是二进制可执行文件或具有自己有效 shebang 行的脚本,那么您可以简单地将命令更改source
为其 POSIX 等效命令,.
以便所有内容都在默认dash
shell 中运行。
答案2
您应该在命令之后运行任何内容$(command -v bash)
(bash
)bash -c ...
,否则整个内容将被视为要由的文件进行解释bash
。
做:
"$(command -v bash)" -c 'source ...'
因此,在crontab
:
01 22 * * * "$(command -v bash)" -c 'source ...'