我可以在哪里设置crontab将使用的环境变量?

我有一个crontab每小时运行一次。运行它的用户在.bash_profile中具有环境变量,当用户从终端运行作业时起作用,然而,显然这些不会在crontab运行时被拾取。

我已经尝试在.profile.bashrc中设置它们,但它们似乎仍然没有被拾取。有人知道我可以把crontab可以获取的环境变量放在哪里吗?

382870 次浏览

让'cron'运行一个shell脚本,在运行命令之前设置环境。

总是这样。

#   @(#)$Id: crontab,v 4.2 2007/09/17 02:41:00 jleffler Exp $
#   Crontab file for Home Directory for Jonathan Leffler (JL)
#-----------------------------------------------------------------------------
#Min     Hour    Day     Month   Weekday Command
#-----------------------------------------------------------------------------
0        *       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/hourly
1        1       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/daily
23       1       *       *       1-5     /usr/bin/ksh /work1/jleffler/bin/Cron/weekday
2        3       *       *       0       /usr/bin/ksh /work1/jleffler/bin/Cron/weekly
21       3       1       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/monthly

~/bin/Cron中的脚本都是指向单个脚本'runcron'的链接,它看起来像:

:       "$Id: runcron.sh,v 2.1 2001/02/27 00:53:22 jleffler Exp $"
#
#       Commands to be performed by Cron (no debugging options)


#       Set environment -- not done by cron (usually switches HOME)
. $HOME/.cronfile


base=`basename $0`
cmd=${REAL_HOME:-/real/home}/bin/$base


if [ ! -x $cmd ]
then cmd=${HOME}/bin/$base
fi


exec $cmd ${@:+"$@"}

(使用较旧的编码标准编写-现在,我会使用shebang '#!开头说。)

“~ /。Cronfile '是我个人资料的一个变种,供cron使用——严格地说,没有交互,也没有为了吵闹而产生的回声。您可以安排执行.profile等等。(REAL_HOME的东西是我的环境的一个人工制品-你可以假装它是相同的$HOME。)

因此,这段代码读取适当的环境,然后从我的主目录执行非cron版本的命令。例如,我的'weekday'命令是这样的:

:       "@(#)$Id: weekday.sh,v 1.10 2007/09/17 02:42:03 jleffler Exp $"
#
#       Commands to be done each weekday


# Update ICSCOPE
n.updics

'daily'命令更简单:

:       "@(#)$Id: daily.sh,v 1.5 1997/06/02 22:04:21 johnl Exp $"
#
#       Commands to be done daily


# Nothing -- most things are done on weekdays only


exit 0

当从命令行运行crontab -e时,可以在crontab本身中定义环境变量。

LANG=nb_NO.UTF-8
LC_ALL=nb_NO.UTF-8
# m h  dom mon dow   command


* * * * * sleep 5s && echo "yo"

此特性仅适用于特定的cron实现。Ubuntu和Debian目前使用vixie-cron,允许在crontab文件(也是GNU mcron)中声明这些。

ArchlinuxRedHat使用cronie,其中允许声明环境变量,并将在cron.log中抛出语法错误。每个条目都可以采取变通措施:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"

对于这个问题,我还有一个解决方案:

0 5 * * * . $HOME/.profile; /path/to/command/to/run

在这种情况下,它将选择你的$HOME/.profile文件中定义的所有环境变量。

当然$HOME也没有设置,你必须用你的$HOME的完整路径替换它。

在@carestad示例的基础上展开(我觉得更简单),使用cron运行脚本,并将环境放在脚本中。

在crontab -e文件中:

SHELL=/bin/bash


*/1 * * * * $HOME/cron_job.sh

cron_job.sh文件:

#!/bin/bash
source $HOME/.bash_profile
some_other_cmd

.bash_profile源文件后面的任何命令都将拥有您的环境,就像您登录了一样。

展开@Robert Brisita刚刚展开,如果你不想在脚本中设置配置文件的所有变量,你可以在脚本顶部选择要导出的变量

在crontab -e文件中:

SHELL=/bin/bash


*/1 * * * * /Path/to/script/script.sh

在script.sh

#!/bin/bash
export JAVA_HOME=/path/to/jdk


some-other-command

对于我来说,我必须为php应用程序设置环境变量。我通过向crontab添加以下代码来解决这个问题。

$ sudo  crontab -e

定时任务:

ENVIRONMENT_VAR=production


* * * * * /home/deploy/my_app/cron/cron.doSomethingWonderful.php

在doSomethingWonderful.php我可以得到的环境值:

<?php
echo $_SERVER['ENVIRONMENT_VAR']; # => "production"

我希望这能有所帮助!

另一种方式——受到这个答案的启发——“注入”;变量如下(以fcron为例):

%daily 00 12 \
set -a; \
. /path/to/file/containing/vars; \
set +a; \
/path/to/script/using/vars

help set:

-a标记已修改或创建用于导出的变量。

使用+而不是-会导致这些标志被关闭。

因此,set -set +之间的所有内容都被导出到env,然后可用于其他脚本,等等。如果不使用set,变量将只在set中获取。

除此之外,当程序需要一个非根帐户来运行,但你需要在其他用户的环境中使用一些变量时,传递变量也很有用。下面是一个传入nullmailer vars来格式化电子邮件头的例子:

su -s /bin/bash -c "set -a; \
. /path/to/nullmailer-vars; \
set +a; \
/usr/sbin/logcheck" logcheck

/etc/environment中设置变量在Ubuntu中也适用。从12.04开始,/etc/environment中的变量为cron加载。

无论你在crontab中设置了什么,都将在cronjob中可用,既可以直接使用,也可以使用脚本中的变量。

在cronjob的定义中使用它们

你可以配置crontab,以便它设置can cronjob使用的变量:

$ crontab -l
myvar="hi man"
* * * * * echo "$myvar. date is $(date)" >> /tmp/hello

现在文件/tmp/hello显示如下内容:

$ cat /tmp/hello
hi man. date is Thu May 12 12:10:01 CEST 2016
hi man. date is Thu May 12 12:11:01 CEST 2016

在cronjob运行的脚本中使用它们

你可以配置crontab,以便它设置脚本可以使用的变量:

$ crontab -l
myvar="hi man"
* * * * * /bin/bash /tmp/myscript.sh

并说脚本/tmp/myscript.sh是这样的:

echo "Now is $(date). myvar=$myvar" >> /tmp/myoutput.res

它生成一个文件/tmp/myoutput.res,显示:

$ cat /tmp/myoutput.res
Now is Thu May 12 12:07:01 CEST 2016. myvar=hi man
Now is Thu May 12 12:08:01 CEST 2016. myvar=hi man
...

而不是

0  *  *  *  *  sh /my/script.sh

使用bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'

如果你通过cron开始执行脚本:

#!/bin/bash -l

它们应该拾取你的~/.bash_profile环境变量

我尝试了大部分提供的解决方案,但一开始都没用。然而,事实证明,并不是解决方案失败了。显然,我的~/.bashrc文件以以下代码块开始:

case $- in
*i*) ;;
*) return;;
esac
这基本上是一个case statement,它检查当前shell中的当前选项集,以确定shell是交互式运行的。 如果shell恰好是交互式运行的,那么它将继续查找~/.bashrc文件。 然而,在cron调用的shell中,$-变量不包含指示交互性的i值。 因此,~/.bashrc文件永远不会得到完全的源。因此,环境变量从未设置过。 如果这恰好是您的问题,请按以下方式注释掉代码块并重试:

# case $- in
#     *i*) ;;
#     *) return;;
# esac

我希望这对你有用

我在我的macbook中使用Oh-my-zsh,所以我已经尝试了很多方法来让crontab任务运行,但最后,我的解决方案是在运行命令之前前置.zshrc

*/30 * * * * . $HOME/.zshrc; node /path/for/my_script.js

此任务每30分钟运行一次,并使用.zshrc配置文件执行我的节点命令。

别忘了在$HOME变量前加上点。

你也可以在命令前加上env注入环境变量,如下所示:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand

对我来说,我必须在NodeJS文件中指定路径。

// did not work!!!!!
require('dotenv').config()

而不是

// DID WORK!!
require('dotenv').config({ path: '/full/custom/path/to/your/.env' })

不幸的是,crontab的环境变量范围非常有限,因此每次运行corntab时都需要导出它们。

一个简单的方法是下面的例子,假设你的env变量在一个名为env的文件中,然后:

* * * * * . ./env && /path/to_your/command

这个. ./env部分将导出它们,然后它们在相同的命令范围内使用

  • 全局设置env
sudo sh -c "echo MY_GLOBAL_ENV_TO_MY_CURRENT_DIR=$(pwd)" >> /etc/environment"
  • 添加计划作业以启动脚本
crontab -e


*/5 * * * * sh -c "$MY_GLOBAL_ENV_TO_MY_CURRENT_DIR/start.sh"

=)

以上所有解决方案都很有效。

当环境变量中有任何特殊字符时,就会产生问题。

我找到了解决方案:

eval $(printenv | awk -F= '{print "export " "\""$1"\"""=""\""$2"\"" }' >> /etc/profile)

对我有用的(基于debian):

  1. 创建一个包含所有需要的env变量的文件:

    < p > # !/bin/bash < br > env | grep VAR1= >/etc/environment < br > env | grep VAR2= >/etc/environment < br > env | grep VAR3= >/etc/environment < br > < / p >
  2. 然后构建crontab内容,在调用需要它的脚本之前调用env文件,因此启动cron服务

    (crontab -l;Echo '* * * * *。/etc/environment;/usr/local/bin/python /mycode.py;/var/log/cron-1.log 2>&1') | crontab
    Service cron start

    . Service cron start

    . Service cron start

注意:对于python用例,一定要调用整个python路径,否则可能会调用错误的python,产生无意义的语法错误

我在查看与标题匹配的类似问题时发现了这个问题,但我被systemd或docker使用的环境文件语法困住了:

FOO=bar
BAZ=qux
这对Vishal的精彩回答不起作用,因为它们不是bash脚本(注意缺少export)。
我使用的解决方案是将每一行读入xargs并在运行命令

之前导出它们
0 5 * * * export $(xargs < $HOME/.env); /path/to/command/to/run