Skip to content

Instantly share code, notes, and snippets.

Last active March 17, 2023 16:11
Show Gist options
  • Save nickjacob/9909574 to your computer and use it in GitHub Desktop.
Save nickjacob/9909574 to your computer and use it in GitHub Desktop.
execute arbitrary bash code/variable substitution in systemd units
Description=Demonstrate Bash
ExecStartPre=/usr/bin/bash -c "/usr/bin/systemctl set-environment MYVAR=$(( 2 + 2 ))"
ExecStart=/usr/bin/echo "2 + 2 = ${MYVAR}"
Copy link

gdamjan commented Jul 24, 2017

The files listed with this directive will be read shortly before the process is executed (more specifically, after all processes from a previous unit state terminated. This means you can generate these files in one unit state, and read it with this option in the next).

Copy link

tzkmx commented Oct 18, 2017

The scope of this variables is at systemd manager, so they are available to all systemd units, you can clean it with ExecStop directive invoking systemctl unset-environment. Also, you can use templated units, and use the variable %i to populate a different variable for every different instance thus avoiding variables collision without copypasting unit files.

Copy link

katcaola commented Jan 25, 2018

Must you use ExecStartPre=/usr/bin/bash or ExecStart=/usr/bin/echo ?
Could you use ExecStartPre=/bin/sh?

Copy link

a0s commented Jun 14, 2018


Copy link

@katcaola Yes. The binary just has to be given with an absolute path.

Copy link

thx 👍

Copy link

Thanks! Used it to dynamically set a USB Ethernet dongle to a separate namespace:

Copy link

dtrv commented May 22, 2020

Note it won't work if user is not root (i.e. if you define "User" in [Service] section). It can be fixed with "PermissionsStartOnly=true", so all commands will be executed as root, and ExecStart command will be run as the defined user as intended.

add --user to systemctl and it works.

Copy link

nice! I have a question why does env variables generated by ExecStartPre can be used by ExecStart?

Copy link

maffe commented Apr 27, 2022

I prefer to write the variable to a file specific to this unit:

ExecStartPre=/usr/bin/bash -c "echo MYVAR=$(( 2 + 2 )) >/dev/shm/demo.env"
ExecStart=/usr/bin/echo "2 + 2 = ${MYVAR}"

Copy link

Thanks. I use it to finally make tigervnc work with SDDM:

Copy link

KalanaDananjaya commented Mar 17, 2023

Beware that there's a pitfall if you have to use %s with your command.
echo (date +%s)
SystemD sees this as user shell and resolve to /bin/sh instead. You need to use %%s to avoid that.

ExecStartPre=/bin/bash -c "echo TIMESTAMP=$(date +%%s) > /tmp/timestamp.txt;"

Although this seems simple, it was quite hard to find this info. ChatGPT was not yielding a correct result either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment