51

Is it possible to give my systemd service more than one argument?

I'd like to execute a program with multiple arguments which have to be decided by the final user.

E.g: ./program arg1 arg2

To start it a single argument app I'd need something like systemctl start arg1@program, where in the service definition I have ExecStart = /usr/bin/program ℅i.

Thanks!

  • 1
    Sounds like what you want is a config file. – Daniel B Mar 14 '14 at 10:27
  • I need to change it on the go. Do I strictly need a conf file? – peperunas Mar 14 '14 at 10:33
  • @peperunas you don't need a conf file, see my answer which works without any extra files – nonagon Jan 4 '18 at 16:23
40

Yes you can! Define them in a file somewhere and add them to EnvironmentFile in your systemd Service. For example, say the contents of /etc/.progconf are:

ARG1=-o
ARG2=--verbose

And your .service file:

EnvironmentFile=/etc/.progconf
ExecStart = /usr/bin/prog $ARG1 $ARG2

You can write to that file if you need to change them on the go. A service shouldn't change its options very often, maybe consider autostarting or cron if you need to achieve that.

For more examples check: https://wiki.archlinux.org/index.php/Systemd/Services

| improve this answer | |
  • Heh, quite handy, didn't think of that. I have to agree though: Service parameters don't change on a regular basis, and neither do their config files. – Daniel B Mar 14 '14 at 11:55
  • if the service file uses environment variables, can you say VAR1=... VAR2=... systemctl start foobar.service to pass the variables? – Johannes Schaub - litb Jun 10 '15 at 18:16
  • Yes, I believe you can – platforma Jun 11 '15 at 11:31
  • 6
    @JohannesSchaub-litb, no, you can't. There is a PassEnvironment directive, but it takes variables from the systemd process (normally PID 1), not from systemctl. Environment variables from the systemctl process don't get propagated to the service being started. – cjm Mar 31 '16 at 19:55
  • 2
    But upstart can run multiple instances of the same service, with different parameters. For example a mail server on eth0 and another instance of said mailserver on eth1, passing the parameter to upstart and managing them as separate services. Can systemd do this? – LtWorf Jan 26 '17 at 10:03
21

I wanted to do the same thing, but without a separate file for each combination of arguments. I found that I could pass one long argument with spaces and then use systemd's environment variable space-splitting feature to separate the arguments.

I made a service with filename argtest@.service (note the trailing 'at sign' which is required when a service takes arguments).

[Unit]
Description=Test passing multiple arguments

[Service]
Environment="SCRIPT_ARGS=%I"
ExecStart=/tmp/test.py $SCRIPT_ARGS

I run this with sudo systemctl start argtest@"arg1 arg2 arg3".service and it passes arg1, arg2 and arg3 as separate command-line arguments to test.py.

| improve this answer | |
  • "note the trailing ampersand": I find no ampersand in your reply. Can you edit your reply to be clearer on this point? – Patrick Mevzek Apr 4 '18 at 23:12
  • Yes, sorry about that! – nonagon Apr 5 '18 at 2:20
  • I think the @ is only needed when you use the %I as you do. It's an instance of the service. – Toby Apr 9 '18 at 12:21
  • Agreed, I just ran into a few blog posts which omitted it. I'll clarify in my answer. – nonagon Apr 9 '18 at 15:31
  • This doesn't seem to work from within another service. I tried Wants=argtest@"arg1 arg2".service and only the first argument was passed. – Roger Dueck Jun 18 '19 at 22:05
1

Easiest I have found is:

ExecStart=/bin/bash -c "\"/path/with spaces/to/app\" arg1 arg2 arg3 \"arg with space\""

Keeps it all self contained.

Having said that, I have found that at least on Ubuntu 18.04 LTS, I don't even need to do that, I can do this and it works fine:

ExecStart="/path/with spaces/to/app" arg1 arg2 arg3 "arg with space"

$vars work as arguments with this pattern as well.

| improve this answer | |
0

Tell your users to override the service by creating a drop-in snippet through the use of the edit option in systemctl.

Firstly, start with some sane defaults. Let's assume the ExecStart part of your service declares the following:

[Service]
ExecStart=./program arg1

Now any user of this service can decide that they want to use a different set of arguments for running the program. They can do that by creating a drop-in snippet with:

systemctl edit myservice.service

In the new file, they simply write the following to override the ExecStart:

[Service]
ExecStart=
ExecStart=./program arg1 arg2

The benefit of doing it this way is that the end result does not involve modifying the system-installed service which may conflict with some package managers.

And that's it!

Now just reload systemd (systemctl daemon-reload) and restart the service (systemctl restart myservice.service).

When the service restarts, it will always also load the user's modifications.

I hope that helps


Sources:

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.