Cron 不使用其 crontab 用户的路径,而是有自己的路径。通过PATH=/foo/bar
在 crontab 的开头添加可以轻松更改它,经典的解决方法是始终使用 cron 运行的命令的绝对路径,但是 cron 的默认 PATH 定义在哪里?
我在 Arch 系统 (cronie 1.5.1-1) 上创建了一个包含以下内容的 crontab,并在 Ubuntu 16.04.3 LTS 机器上进行了测试,结果相同:
$ crontab -l
* * * * * echo "$PATH" > /home/terdon/fff
打印出来的是:
$ cat fff
/usr/bin:/bin
但为什么?默认的系统范围路径在 中设置/etc/profile
,但包括其他目录:
$ grep PATH= /etc/profile
PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"
/etc/environment
或中没有其他相关的内容/etc/profile.d
,我认为 cron 可能会读取其他文件:
$ grep PATH= /etc/profile.d/* /etc/environment
/etc/profile.d/jre.sh:export PATH=${PATH}:/usr/lib/jvm/default/bin
/etc/profile.d/mozilla-common.sh:export MOZ_PLUGIN_PATH="/usr/lib/mozilla/plugins"
/etc/profile.d/perlbin.sh:[ -d /usr/bin/site_perl ] && PATH=$PATH:/usr/bin/site_perl
/etc/profile.d/perlbin.sh:[ -d /usr/lib/perl5/site_perl/bin ] && PATH=$PATH:/usr/lib/perl5/site_perl/bin
/etc/profile.d/perlbin.sh:[ -d /usr/bin/vendor_perl ] && PATH=$PATH:/usr/bin/vendor_perl
/etc/profile.d/perlbin.sh:[ -d /usr/lib/perl5/vendor_perl/bin ] && PATH=$PATH:/usr/lib/perl5/vendor_perl/bin
/etc/profile.d/perlbin.sh:[ -d /usr/bin/core_perl ] && PATH=$PATH:/usr/bin/core_perl
毫不奇怪,中的任何文件都没有任何相关内容,也没有在任何文件/etc/skel
中设置:/etc/cron*
$ grep PATH /etc/cron* /etc/cron*/*
grep: /etc/cron.d: Is a directory
grep: /etc/cron.daily: Is a directory
grep: /etc/cron.hourly: Is a directory
grep: /etc/cron.monthly: Is a directory
grep: /etc/cron.weekly: Is a directory
/etc/cron.d/0hourly:PATH=/sbin:/bin:/usr/sbin:/usr/bin
那么,cron 用户 crontab 的默认 PATH 是在哪里设置的呢?它cron
本身是硬编码的吗?它不会为此读取某种配置文件吗?
答案1
它被硬编码在源代码(该链接指向当前的 Debian cron
— 考虑到实现的多样性cron
,很难选择其中之一,但其他实现可能类似):
#ifndef _PATH_DEFPATH
# define _PATH_DEFPATH "/usr/bin:/bin"
#endif
cron
不从配置文件中读取默认路径;我想原因是它支持指定已经使用的路径PATH=
在任何 cronjob 中使用的路径,因此无需在其他地方指定默认值。 (使用硬编码默认值如果没有其他内容指定作业条目中的路径.)
答案2
添加到 Stephen Kitt 的答案中,有一个PATH
在 Ubuntu 上设置 cron 的配置文件,以及cron
忽略使用PATH
硬编码的默认值(或PATH
在 crontab 本身中设置)。该文件是/etc/environment
. Notecron
的PAM配置:
$ cat /etc/pam.d/cron
...
# Read environment variables from pam_env's default files, /etc/environment
# and /etc/security/pam_env.conf.
session required pam_env.so
# In addition, read system locale information
session required pam_env.so envfile=/etc/default/locale
...
这很容易验证。添加一个变量/etc/environment
,例如,作为 cronjobfoo=bar
运行并观察输出中显示的内容。env > /tmp/foo
foo=bar
但为什么?默认的系统范围路径在 /etc/profile 中设置,但还包括其他目录:
$ grep PATH= /etc/profile PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"
在 Arch Linux 中确实如此,但在 Ubuntu 中,基础PATH
设置为/etc/environment
.文件附加/etc/profile.d
到现有文件上PATH
,您可以将其附加到~/.pam_environment
.我有关于 Arch 行为的错误。
不幸的是,/etc/pam.d/cron
不包括读取~/.pam_environment
。奇怪的是,/etc/pam.d/atd
做包含该文件:
$ cat /etc/pam.d/atd
#
# The PAM configuration file for the at daemon
#
@include common-auth
@include common-account
session required pam_loginuid.so
@include common-session-noninteractive
session required pam_limits.so
session required pam_env.so user_readenv=1
...但是通过运行的命令at
显然继承了创建作业时可用的环境at
(例如,env -i /usr/bin/at ...
似乎在非常干净的环境中运行作业)。
修改/etc/pam.d/cron
为 hasuser_readenv=1
似乎不会造成任何问题,并且变量 in~/.pam_environment
开始显示良好(当然PATH
,除了 )。
总而言之,为 cron 设置环境变量似乎是一件很麻烦的事情。最好的地方似乎是作业规范本身,如果只是因为您不知道 cron 可能决定忽略哪些继承的环境变量(无需阅读源代码)。