Search code examples
linuxbashenvironment-variablessystemd

How can I determine the precise set of environment variables a systemd EnvironmentFile would set?


systemd has an EnvironmentFile directive, which sets environment variables from a file's contents based on a number of rules, which are not quite equivalent to how a shell would parse that file.

How can I parse a systemd EnvironmentFile in exactly the same way that systemd itself would?


Solution

  • The surest thing is to let systemd parse the file itself, via a transient service. Thus:

    # emit a NUL-delimited set of key=value definitions for environment variables defined by a set of files
    newVarsForFile_nullsep() {
      local -a extraParams=( ); local file
      (( $# )) || return 0 # no files specified, nothing to do
      for file in "$@"; do
        extraParams+=( --property=EnvironmentFile="$file" )
      done
      comm -z -23 \
        <(sort -z < <(systemd-run --user --pipe "${extraParams[@]}" grep -zvE '^INVOCATION_ID=' /proc/self/environ </dev/null)) \
        <(sort -z < <(systemd-run --user --pipe grep -zvE '^INVOCATION_ID=' /proc/self/environ </dev/null) )
    }
    
    # emit code that can be eval'd in an instance of bash to precisely define the exact variables
    newVarsForFile_shellscript() {
      while IFS= read -r -d '' vardef; do
        printf '%s=%q\n' "${vardef%%=*}" "${vardef#*=}"
      done < <(newVarsForFile_nullsep "$@")
    }
    

    Thereafter, one may invoke (as an example):

    newVarsForFile_shellscript /etc/conf.d/*.conf
    

    ...to emit a shell script fragment which, when executed by bash, will set all the same environment variables that adding the relevant EnvironmentFiles to a service definition would set.