22

I want to specify an Environment systemd directive containing =, e.g.

Environment=CATALINA_OPTS=-Dappserver.home=/var/lib/archiva/apache-tomcat-current -Dappserver.base=/var/lib/archiva/apache-tomcat-current

and get the error

[/lib/systemd/system/archiva.service:10] Invalid environment assignment, ignoring: CATALINA_OPTS=-Dappserver.home\=/var/lib/archiva/apache

in journalctl -xe. I tried to quote with " and ' and to escape = with \ without success. This seems undocumented.

0

3 Answers 3

44

I think your problem is due the space in the environment variable's contents. Looking at the examples from the systemd docs, an assignment should be a single string:

Example:

Environment="ONE=one" 'TWO=two two'
ExecStart=/bin/echo $ONE $TWO ${TWO}

This will execute /bin/echo with four arguments: one, two, two, and two two.

Example:

Environment=ONE='one' "TWO='two two' too" THREE=
ExecStart=/bin/echo ${ONE} ${TWO} ${THREE}
ExecStart=/bin/echo $ONE $TWO $THREE

This results in echo being called twice, the first time with arguments 'one', 'two two' too, , and the second time with arguments one, two two, too.

I tested this with the following service (note the quotes around the entire assignment):

[Unit]
Description=My Daemon

[Service]
Environment='CATALINA_OPTS=-Dappserver.home=/var/lib/archiva/apache-tomcat-current -Dappserver.base=/var/lib/archiva/apache-tomcat-current'
ExecStart=/bin/echo ${CATALINA_OPTS}

[Install]
WantedBy=multi-user.target

And got the desired output in journalctl:

Apr 26 08:19:29 laptop echo[28439]: -Dappserver.home=/var/lib/archiva/apache-tomcat-current -Dappserver.base=/var/lib/archiva/apache-tomcat-current

Of course, it would be simpler to use EnvironmentFile instead. Replacing the Environment with the following gave the same desired result:

EnvironmentFile=/tmp/foo

Where /tmp/foo contained (note the lack of quotes):

CATALINA_OPTS=-Dappserver.home=/var/lib/archiva/apache-tomcat-current -Dappserver.base=/var/lib/archiva/apache-tomcat-current
10
  • When it comes to quoting quotes (e.g. by using CATALINA_OPTS in systemd environment for Apache tomcat 7.0.61) using EnvironmentFile really is the way to go. Thanks! Apr 26, 2015 at 17:11
  • What is the standard/ convention directory for keeping an EnvironmentFile on Ubuntu? On other systems I've seen /etc/sysconfig/
    – Davos
    Aug 29, 2017 at 1:20
  • 2
    @Davos a reasonable place would be /etc/default. Files there have been historically used for placing environment variables for corresponding init scripts.
    – muru
    Aug 29, 2017 at 1:21
  • I have this file already on my system /etc/environment which contains a PATH variable, would appending to that be sensible?
    – Davos
    Aug 29, 2017 at 1:22
  • 1
    @Davos that's systemwide. If there's no problem with the variable being set for practically every process, sure. Note that /etc/environment is not processed by a shell; aside from simple variable assignment, its syntax is very different from the systemd syntax noted above or general shell syntax.
    – muru
    Aug 29, 2017 at 1:25
1

In addition to what the accepted answer says, if you put your environment variables into a drop-in file, then you need to use the following syntax to make sure they are not all treated as one argument to your program:

env.conf drop-in file

[Service]
Environment='CATALINA_OPTS=-Dappserver.home=/var/lib/archiva/apache-tomcat-current -Dappserver.base=/var/lib/archiva/apache-tomcat-current'

unit.service

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/echo $CATALINA_OPTS

[Install]
WantedBy=multi-user.target

I don't know why using just $ENV_NAME worked for me, and ${ENV_NAME} didn't, and I couldn't find anything documenting this difference. All I can say is that $ENV_NAME syntax worked to treat each argument in the variable which is separated by space, as distinct arguments, whereas the ${ENV_NAME}, treated them all as one argument.

Maybe using echo is not the best way to tell this difference. I suggest anyone looking to test it to use something like /usr/bin/printf "%s\n" ${ENV_NAME} vs /usr/bin/printf "%s\n" $ENV_NAME, and see what they get.

Creating drop-in files

One can create a drop-in file by using the edit command for systemctl. For example in the case of this question, the command would be:

sudo systemctl edit archiva.service

You can also create one like I did above by adding a custom file to /lib/systemd/system/archiva.service.d/ folder


EDIT

I found the documentation on observed environmental variable behavior, thanks to another answer:

Basic environment variable substitution is supported. Use "${FOO}" as part of a word, or as a word of its own, on the command line, in which case it will be erased and replaced by the exact value of the environment variable (if any) including all whitespace it contains, always resulting in exactly a single argument. Use "$FOO" as a separate word on the command line, in which case it will be replaced by the value of the environment variable split at whitespace, resulting in zero or more arguments. For this type of expansion, quotes are respected when splitting into words, and afterwards removed.

-1

Alternative solution

"C escapes supported in command lines and environment variables"

  • "\n" newline
  • "\r" carriage return
  • "\t" tab
  • "\v" vertical tab
  • "\" backslash
  • """ double quotation mark
  • "'" single quotation mark
  • "\s" space
  • "\xxx" character number xx in hexadecimal encoding
  • "\nnn" character number nnn in octal encoding

https://www.freedesktop.org/software/systemd/man/systemd.service.html

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .