环境: centos6
分析:
一般来讲,都是因为在某个环节把环境变量给清了:
- 要么是应用程序为了安全,自己清理了环境变量;这种情况多半在应用程序的配置中允许设置保留哪些环境变量(如:sudo程序)
- 要么是外部脚本启动应用程序时(使用env命令)把环境变量给清了;如: service命令启动服务(如: crond)时就使用env清理了环境变量:
|
env -i PATH=/sbin:/usr/sbin:/bin:/usr/bin TERM=xterm-256color /etc/init.d/crond start |
解决办法: 要么不清环境变量,要么添加自己期望保留的环境变量
根据上面的理论,修改了/sbin/service 添加了自己想保留的环境变量,如下:
|
env -i PATH=/sbin:/usr/sbin:/bin:/usr/bin TERM=xterm-256color MY_VAR_NAME=$MY_VAR_NAME /etc/init.d/crond start |
(其实,如果直接使用/etc/init.d/crond start 来启动crond是和 /sbin/service 没有一毛钱关系的)
测试发现,在crond中启动的程序,依然获取不到想要的环境变量;根据上面理论,基本是crond把环境变量给清理了,那么这个该怎么办呢?
解决办法1: 给每个cron 任务写一个wrapper,在wrapper中设置自己需要的环境变量,wrapper.sh如下:
|
#!/bin/bash source /path/to/my/env/file $* |
这样,只需要在每条cron的前面添加 wrapper.sh 就行了,如下:
|
* * * * * /tmp/wrapper.sh /bin/echo 1 >/tmp/debug.txt |
cron执行log如下:
|
Jul 20 19:21:01 bs2 CROND[42036]: (root) CMD (/tmp/wrapper.sh /bin/echo 1 >/tmp/debug.txt) |
看起来还不错:)
但是,我有上百条cron,修改起来好是麻烦;其实通过写脚本来添加,还好;不过每次添加新的cron都要记着先写/tmp/wrapper.sh 有些繁琐,忘记了怎么办?
解决办法2:
据说cron会参考环境变量SHELL,而且可以在crontab中设置这个SHELL,你们crond应该就是用这个东西启动子进程的,否则要这个干啥?如果我在crontab中如下设置:
其不很方便?
测试发现并不如此简单,原因如下:
- 如果SHELL设置为/tmp/wrapper.sh 则crond是这么使用的:
/tmp/wrapper.sh -c “/bin/echo 1 >/tmp/debug.txt”
显然,我的wrapper.sh中没有处理-c选项; 简单,我也不关心这个,直接shift掉不就完了?wrapper.sh 修改如下:
|
#!/bin/bash source /path/to/my/env/file shift $* |
测试发现找不到/tmp/debug.txt;但是,在cron的邮件中找到了 “ 1 >/tmp/debug.txt”(这是cron任务的输出); 分析发现,我们的wrapper.sh 似乎并不认识 “>” ,难怪,我的wrapper.sh确实不是一个shell,不能解析 “>”, 但是如果为此写一个认识 “>” 的shell也不值当的呀!还是让bash自己来干吧
- 我们上面已经说了,crond使用了bash的-c选项,-c选项就是把字符串当做shell来执行,我何不学下呢?如下:
|
#!/bin/bash shift source /path/to/my/env/file /bin/bash -c "$*" |
嗯,就是这样子的
附录: vixiecron 的源码(src/do_command.c)中(函数: static int child_process(entry * e, char **jobenv); )是这么运行任务的:
|
execle(shell, shell, "-c", e->cmd, (char *) 0, jobenv); |
man execle可以知道:
|
int execle(const char *path, const char *arg, ..., char * const envp[]); |
|
The execle() function also specifies the environment of the executed process by following the NULL pointer that terminates the list of arguments in the argument list or the pointer to the argv array with an additional argument. This additional argument is an array of pointers to null-terminated strings and must be terminated by a NULL pointer. The other functions take the environment for the new process image from the external variable environ in the current process. |
其中,最后一个参数是要执行的shell的环境变量,没有继承父进程的环境变量(虽然没有专门clear所有的环境变量)
其实,完全可以在crontab file的前面定义想要的环境变量的,这里定义的环境变量不会被清空