Cron doesn't use the path of the user whose crontab it is and, instead, has its own. It can easily be changed by adding PATH=/foo/bar
at the beginning of the crontab, and the classic workaround is to always use absolute paths to commands run by cron, but where is cron's default PATH defined?
I created a crontab with the following contents on my Arch system (cronie 1.5.1-1) and also tested on an Ubuntu 16.04.3 LTS box with the same results:
$ crontab -l
* * * * * echo "$PATH" > /home/terdon/fff
That printed:
$ cat fff
/usr/bin:/bin
But why? The default system-wide path is set in /etc/profile
, but that includes other directories:
$ grep PATH= /etc/profile
PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"
There is nothing else relevant in /etc/environment
or /etc/profile.d
, the other files I thought might possibly be read by 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
There is also nothing relevant in any of the files in /etc/skel
, unsurprisingly, nor is it being set in any /etc/cron*
file:
$ 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
So, where is cron's default PATH for user crontabs being set? Is it hardcoded in cron
itself? Doesn't it read some sort of configuration file for this?
cron
to look at/etc/profile
, or care about any particular shell. A better question is why doesn'tcron
readPATH
fromlogin.defs
(on Linux) orlogin.conf
(on *BSD). I suppose it's ultimately an implementation detail. – Satō Katsura Oct 31 '17 at 13:02/etc/profile
because it uses the same syntax (var=value
) ascron
itself, so it would be easy enough to do and/etc/profile
is, to my knowledge, very widespread. What surprised me is that I couldn't find it being set anywhere so it looked like it was hard coded. As is indeed the case, as Stephen explained below. – terdon Oct 31 '17 at 13:05zsh
as their interactive shell don't care about/etc/profile
(which is specific tobash
) – Basile Starynkevitch Oct 31 '17 at 13:16profile
files are only read by login shells, anyway. These may, or may not be interactive. – terdon Oct 31 '17 at 13:20strings
against a program can help find these hard-coded values, too. – jrw32982 Nov 02 '17 at 02:34crontab
reads a configuration file is irrelevant to what configuration is used bycron
itself:crontab
is just a program that is used to update the database of job tables used bycron
and signalcron
when it has changed.cron
(if the version in use is anywhere near standard) should be reading/etc/crontab
at startup. – Jules Nov 08 '17 at 00:33/etc/profile
uses the same syntax ascron
for setting the path, but note that it is written in a general purpose programming language that is able to manipulate references to variables and to evaluate generated code, so in the general case extracting the path information from it is much more complex than whatcron
does with its own files. – Jules Nov 08 '17 at 00:38/etc/profile
should be written in POSIXsh
and is sourced (.
) by POSIX compliant (or semi-compliant, like bash, zsh etc.) shells. Given that cron also usessh
to run its commands, it would be trivial to source it each time it launches itssh
. – terdon Nov 08 '17 at 08:29sh
is not the "user-specified" shell, it is the default shell on *nix systems and is usually either a simple POSIX-compliant shell likedash
, or actual bourne-sh orbash
running in POSIX mode. either way, cron defaults to/bin/sh
so it could just as well have defaulted to reading/etc/profile
or, as Sato correctly pointed out,login.[defs|conf]
. – terdon Nov 08 '17 at 10:17