在 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 脚本的末尾。

让我们创建一个名为 /home/tpoint/wrap_printenvs.sh 的新 shell 脚本:

#!/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

使用登录 shell 运行作业

为了模拟运行 crontab 条目时的相同顺序,我们可以使用解释器(例如 bash)来运行脚本。当 Bash 作为登录 shell 工作时,它会读取诸如 ~/.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 和登录 shell。

* * * * * 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 作业可能难以理解。

像 Fedora 和 Arch Linux 这样的程序提供了 cron 的 cron 守护程序实现;使用这些实现,我们可以在 /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 作业设置环境变量值的各种方法。

我们之前探讨了如何使用 $BASH_ENV 环境变量在作业开始之前运行脚本。此设置允许我们包含来自其他来源的环境变量,例如 /etc/bashrc。

接下来,我们看到我们可以将一个作业包装在另一个作业中,在执行原始作业之前设置和加载所有所需的环境变量。

我们现在已经学习了如何单独设置环境变量值,并将它们直接写入 crontabs 文件。

更新于:2023年1月3日

5K+ 次浏览

启动您的 职业生涯

通过完成课程获得认证

开始
广告