3 ms·
> That does require you to still know what the default environment is, but it is a mostly completely clean environment, without any influence from any shell. O
by simoncion 4mo ago
> That does require you to still know what the default environment is, but it is a mostly completely clean environment, without any influence from any shell.
Odd. This script
#!/bin/bash
set > /tmp/set.txt
when scheduled like so
* * * * * $HOME/bin/testCronScript.sh
Produces this file in /tmp/set.txt which has had a handful of values (HOME, UID, etc) lightly redacted prior to posting here -to remove PII or for length- but its keys are entirely untouched:
BASH=/bin/bash
BASHOPTS=<redacted because long>
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=([0]="0")
BASH_LOADABLES_PATH=/usr/local/lib64/bash:/usr/lib64/bash
BASH_SOURCE=([0]="/home/user/bin/testCronScript.sh")
BASH_VERSINFO=<redacted bash 5.3.x>
BASH_VERSION=<redacted bash 5.3.x>
DIRSTACK=()
EUID=13370
GROUPS=()
HOME=/home/user
HOSTNAME=hostname
HOSTTYPE=x86_64
IFS=$' \t\n'
LANG=en_US.utf8
LOGNAME=user
MACHTYPE=x86_64-pc-linux-gnu
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/bin:/bin:/usr/sbin:/sbin
PPID=1337
PS4='+ '
PWD=/home/user
SHELL=/bin/sh
SHELLOPTS=braceexpand:hashall:interactive-comments
SHLVL=1
TERM=dumb
UID=13370
USER=user
_=/home/user/bin/testCronScript.sh
Seems pretty clean to me. Even when I run this via /etc/crontab, rather than as a user cron job:
* * * * * root /home/user/bin/testCronScript.sh
I get effectively the same results.
Maybe your distro's default cron environment was bad, and you never bothered to check and unset the badness? I'd be surprised if they were unable to make the default environment for Timer Units to be bad.
- jchw 4mo agoRegardless of exactly how clean the environment is, my favorite part of systemd is the fact that there is only one regardless of how something was triggered. Whether a unit is triggered via a mount unit, timer unit, udev rule, it's the same units at the end, so it's the same environment. The same problems that could be caused by a polluted environment in cron can be caused in reverse by a polluted environment elsewhere, when you unwittingly copy a command that depends on some environment being set. If you are using systemd as the service manager, this necessarily doesn't happen because it's all units. (Well, you could still copy something from outside of systemd and run into a similar problem, but at least there's essentially only one set of caveats you have to learn for whatever thing you want executed in the background.) So I guess this isn't so much cron vs systemd timers, but more cron + other init and service supervisors vs systemd init in general.
- simoncion 4mo ago> Regardless of exactly how clean the environment is, my favorite part of systemd is the fact that there is only one regardless of how something was triggered. Whether a unit is triggered via a mount unit, timer unit, udev rule, it's the same units at the end, so it's the same environment. > > The same problems that could be caused by a polluted environment in cron can be caused in reverse by a polluted environment elsewhere, when you unwittingly copy a command that depends on some environment being set. I'm confused about what you need this for? Are you running some utility command that needs the same environment provided by the daemon's service file? If so, any competent init system lets you extend upstream-provided service files. In OpenRC: # tail -n 1000 /etc/*/test-service ==> /etc/conf.d/test-service <== extra_commands="${extra_commands} maintenance" OTHER_THING="overriden other-thing" maintenance () { ebegin "doing maintenance. IV='$INIT_VAR' OT='$OTHER_THING'" set > /tmp/maintenance-set.txt eend 0 } ==> /etc/init.d/test-service <== #!/sbin/openrc-run name="test-service daemon" command=/usr/bin/socat command_user=nobody:nobody command_args="UDP-RECVFROM:6666,fork SYSTEM:'/bin/true'" supervisor=supervise-daemon extra_commands="rebuild" INIT_VAR=${INIT_VAR:-"init var"} OTHER_THING=${OTHER_THING:-"stock other-thing"} depend() { use net } start_pre() { set > /tmp/start-set.txt } rebuild () { ebegin "doing rebuild. IV='$INIT_VAR' OT='$OTHER_THING'" eend 0 } # /etc/init.d/test-service start test-service | * Starting test-service daemon ... [ ok ] # /etc/init.d/test-service maintenance test-service | * doing maintenance. IV='init var' OT='overriden other-thing' ... [ ok ] # /etc/init.d/test-service rebuild test-service | * doing rebuild. IV='init var' OT='overriden other-thing' ... [ ok ] # pgrep --list-full socat 133705 /usr/bin/socat UDP-RECVFROM:6666,fork SYSTEM:/bin/true The environment when the service is starting is effectively identical to the one when our custom function is being called: # diff -u0 /tmp/*-set.txt --- /tmp/maintenance-set.txt 2026-06-02 23:53:19.703048431 -0700 +++ /tmp/start-set.txt 2026-06-02 23:53:15.265094855 -0700 @@ -9 +9 @@ -BASH_LINENO=([0]="410" [1]="0") +BASH_LINENO=([0]="409" [1]="0") @@ -11 +11 @@ -BASH_SOURCE=([0]="/etc/init.d/../conf.d/test-service" [1]="/usr/libexec/rc/sh/openrc-run.sh") +BASH_SOURCE=([0]="/etc/init.d/test-service" [1]="/usr/libexec/rc/sh/openrc-run.sh") @@ -30 +30 @@ -FUNCNAME=([0]="maintenance" [1]="main") +FUNCNAME=([0]="start_pre" [1]="main") @@ -64 +64 @@ -PPID=133712 +PPID=133702 @@ -69 +69 @@ -RC_CMD=maintenance +RC_CMD=start @@ -73 +73 @@ -RC_OPENRC_PID=133710 +RC_OPENRC_PID=133700 @@ -75 +75 @@ -RC_RUNSCRIPT_PID=133711 +RC_RUNSCRIPT_PID=133701 @@ -93 +93 @@ -_='doing maintenance. IV='\''init var'\'' OT='\''overriden other-thing'\''' +_=']' So, if you need to do maintenance for a service on a schedule in the same environment that is provided for starting that service, you can simply extend the service script and use cron to execute that functionality. But. Another thing that confuses me is why you think that SystemD [0] provides anything special here? If you were to create a service file in most any other service manager and start it with cron, you'd get exactly the same environment sanitization as you get for all other services. Given your testimony, I expect that prior to SystemD, you'd have refused to create service files for things like one-off jobs that weren't system services... so why are you okay with it now that you're using SystemD? [0] I spell it "SystemD" not to mock it -as I understand some do- but to distinguish The Systemd Project from systemd(1). It sucks minor ass that the two share the same name, but what can you do?