在Cron作业中加载环境变量
介绍
当crontab运行一个命令时,它不会从~/.bashrc、~/.bash_profile等文件中读取任何环境变量。因为cron从一个非交互式、非登录的shell中运行任务,所以它不需要一个交互式用户 一些应用程序需要环境变量才能正常运行。
我们将讨论从crontab加载环境变量的不同方法。
设置BASH_ENV变量
我们可以通过使用BASH_ENV变量为我们的shell脚本设置环境变量。我们对它进行设置,以便当我们运行作业时,它们由shell脚本来执行。我们可以设置我们的shell,这样当我们打开一个新的终端窗口时,我们就可以得到适合我们系统的设置。我们可以使用BASH_ENV来运行任何shell命令,而不需要知道它的确切名称。
我们将在我们的crontab文件中添加一行,在执行脚本之前运行/etc/profile。
* * * * * BASH_ENV=/etc/profile /home/baeldung/print_envs.sh
注意,这个工作每分钟运行一次。另外,让我们编写/home/baeldung/print_envs.sh脚本,使用printenv–将所有环境变量打印到一个时间文件中。
#!/bin/bash
printenv > /tmp/print_envs_result
Now, after setting execution permission to the script with chmod +x /home/tpoint/print_envs.sh, we’ll wait one minute to see the result:
wc -l /tmp/print_envs_result
38 /tmp/print_envs_result grep PS1= /tmp/print_envs_result
PS1=\u@\h:\w\$
我们可以看到,print_envs脚本加载了38个环境变量。例如,它加载了PS1的值。
你也可以使用BASH_ENV来运行一个自定义的shell命令。我们可以用它来加载多个文件或添加更多的变量。让我们创建一个叫做preload.sh的shell文件,它可以加载四个不同的文件。/etc/profile、~/.bash_profile、~/.bashrc,并导出另一个变量。
#!/bin/bash
. /etc/profile
. ~/.bash_profile
. ~/.bashrc
export LEARNING_FROM=tpoint
现在,我们将修改crontab文件以使用/home/tpoint/preload.sh —
* * * * * BASH_ENV=/home/tpoint/preload.sh /home/tpoint/print_envs.sh
等待一分钟后,我们得到的结果是 —
$ wc -l /tmp/print_envs_result
41 /tmp/print_envs_result
$ grep LEARNING_FROM /tmp/print_envs_result
LEARNING_FROM=tpoint
我们已经注意到,现在有41个环境变量。我们还有一个变量LEARNING_FROM,默认值为 “tpoint”。
用Bash包装工作
假设我们有这样一个crontab文件 —
* * * * * printenv > /tmp/print_envs_result
因为printenv不是一个shell脚本,我们不能用BSH_ENV来加载环境变量值。然而,我们可以用Bash来包装它。我们的做法是在命令前加上bash -c,然后用双引号字符串来包装它。
我们通过在作业前加上bash -c并将作业置于双引号内来实现这一目的。Bash在从传递给脚本的参数中读取命令时使用-c选项。
我们将在我们的脚本中加入bash -c,这样我们就可以检查环境变量BASH_ENV。
* * * * * BASH_ENV=/etc/profile bash -c "printenv > /tmp/print_envs_result"
cron运行作业后,我们可以看到printenv从/etc/profile中加载了所有的环境变量—-。
$ wc -l /tmp/print_envs_result
38 /tmp/print_envs_result
$ grep PS1= /tmp/print_envs_result
PS1=\u@\h:\w\$
如果需要,我们可以添加更多的环境变量,或者我们可以创建另一个shell文件来包括我们想要的额外文件。现在,我们有两个选择。我们可以通过设置一个名为BASH_ENV的环境变量来加载更新的脚本。就像以前一样。相反,让我们把原来的作业从crontabs文件中的当前位置移到我们新的shell脚本的末尾。
让我们创建一个新的shell脚本,称为/home/tpoint/wrap_printenvs.sh –
#!/bin/bash
. /etc/profile
. ~/.bash_profile
. ~/.bashrc
export LEARNING_FROM=tpoint
#now, we run the original job
printenv > /tmp/print_envs_result
最后,我们修改crontab文件,以运行新的脚本 —
* * * * * /home/tpoint/wrap_printenv.sh
与上一节类似,我们可以在结果中看到环境变量——。
$ wc -l /tmp/print_envs_result
41 /tmp/print_envs_result
$ grep LEARNING_FROM /tmp/print_envs_result
LEARNING_FROM=tpoint
使用登录外壳运行作业
为了模仿运行crontab条目时的相同顺序,我们可以使用解释器(例如bash)来运行脚本。当Bash作为登录外壳工作时,它会读取诸如~/.bash_profile、~/.bash_login、/etc/profile和~/.profile等文件。这样,bash shell将加载所有的启动脚本,从这些文件中加载环境变量。我们应该用bash -l -c开始工作,并确保用双引号将其括起来。当我们希望命令处于登录(或交互)模式时,-l参数是必不可少的。
让我们用一个交互式的shell来运行上一节的printenv命令。
* * * * * bash -l -c "printenv > /tmp/print_envs_result"
因为这仍然是一个非交互式终端,bash并没有加载~/.bashrc文件。如果我们也使用BASH_ENV,就可以克服这个问题。
我们将用它来加载~/.bashrc和登录外壳。
* * * * * BASH_ENV=~/.bashrc bash -l -c "printenv > /tmp/print_envs_result"
我们现在需要让cron运行该脚本,然后检查是否有任何环境变量被设置。
$ wc -l /tmp/print_envs_result
41 /tmp/print_envs_result
设置Crontab文件中的每个变量
我们可以在运行命令前使用name=variable语法来设置变量。如果我们想使用多个变量,必须用空格分隔。
我们需要为运行print_envs脚本设置环境变量——。
* * * * * LEARNING_FROM=tpoint LANG=es_US /home/tpoint/print_envs.sh
一分钟后,我们现在可以看到脚本将这些值加载到页面中 —
$ grep -E 'LANG|LEARNING_FROM' /tmp/print_envs_result
LEARNING_FROM=tpoint
LANG=en_US
如果我们想设置很多变量,那么我们最后会有很长的一行代码。如果我们这样做,那么这个cron job可能就很难理解了。
像Fedora和Arch Linux这样的程序,提供了cron daemon的实现;通过这些实现,我们可以在/etc/crontab文件中为所有工作(包括系统范围)定义环境变量。我们将每个环境变量一次性写在一行中,其中没有任何作业。
我们将为所有工作类型定义LEARNING_FROM和LANG
LEARNING_FROM=tpoint
LANG=es_US
* * * * * /home/baeldung/print_envs.sh
正如我们所看到的,该脚本加载了这些变量 —
$ grep -E 'LANG|LEARNING_FROM' /tmp/print_envs_result
LEARNING_FROM=baeldung
LANG=en_US
结论
我们研究了为cron job设置环境变量值的不同方法。
我们之前探讨了如何利用$ BASH_ENV环境变量在工作开始前运行一个脚本。这个设置允许我们包括来自其他来源的环境变量,比如/etc/bashrc。
接下来,我们看到,我们可以将一个作业包裹在另一个作业中,在执行原始作业之前,我们设置并加载所有需要的环境变量。
现在我们已经学会了如何单独设置环境变量值,将它们直接写入crontabs文件中。