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.

muru
  • 197,895
  • 55
  • 485
  • 740
Kalle Richter
  • 6,180
  • 21
  • 70
  • 103

3 Answers3

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
muru
  • 197,895
  • 55
  • 485
  • 740
  • 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! – Kalle Richter Apr 26 '15 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 '17 at 01: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 '17 at 01: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 '17 at 01: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 '17 at 01:25
  • Thanks for the guidance, that's very helpful. I'll use something like /etc/default/ as the EnvironmentFile for this. – Davos Aug 29 '17 at 01:33
  • systemd is so nice..... – whirlwin Feb 13 '20 at 07:53
  • Is it possible to set a variable with a double quote in the value? – lav Mar 20 '20 at 07:48
  • @lav quoting the value with single quotes should work, I guess, but I haven't tested it – muru Mar 21 '20 at 06:23
  • For demonstrations, it would be better to use something like printf "[%s]\n" $ONE $TWO instead of echo to make it more apparent how arguments are interpreted. – Mikko Rantalainen Mar 27 '23 at 12:03
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.

smac89
  • 854
-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

Gary
  • 99