I am curious whether I can print out fully expanded ExecStart/ExecStop command line. Consider following example:

ExecStart=/usr/bin/java $OPTS_COMMON $OPTS $OPTS_LOG $OPTS_DEBUG some.class.Start --param1 ${PARAM1} --param2 ${PARAM2}

I am having quite long command lines with a lot of environment variables involved. If some of the variables becomes wrong (for example by drop-in configuration), service might not start at all. However I do not see fully expanded line with substituted envs anywhere and I struggle to find out what is wrong.

I had no luck googling this and so far the only possibility I found is to modify unit file to run /usr/bin/echo instead of service itself. But that is a bit tiresome. Or even more annoying solution - check every environment variable one-by-one.

Is there some way how to force systemd to show me what is actually attempted to be run?


Unfortunately there is no built in way. To see the final ExecStart you can turn on debugging. Edit the file /etc/systemd/system.conf and set the LogLevel= to debug. Then you will see something like:

java.service About to execute: /usr/bin/java $OPTS_COMMON... This doesn't solve your problem but it is good to see the systemd's specifier replacement. https://www.freedesktop.org/software/systemd/man/systemd.unit.html(specifiers)

But if you really want to get to the bottom of argument replacement you need to look in to here: https://github.com/systemd/systemd/blob/7ce9cc154576e342015eab8c1500790a9ededc01/src/core/execute.c#L2570

  • I was a bit afraid that there is no way how to do it. :/ Thanks anyway. – pystole Sep 21 '16 at 10:57
  • 1
    I found that LogLevel=debug as mentioned above does work, but not until I run this command to reload the systemd manager configuration.: systemctl daemon-reload. – CODE-REaD May 1 '20 at 2:11

Instead of using the command line to execute, use a wrapper script (or binary) with the same command and parameters. Then the wrapper script logs the parameters and then executes the real command.

Like this:

ExecStart=/path/to/wrapper /usr/bin/java $OPTS_COMMON $OPTS $OPTS_LOG $OPTS_DEBUG some.class.Start --param1 ${PARAM1} --param2 ${PARAM2}

The wrapper script itself could be:

for param
    echo "param: $param"
done > $LOGFILE
exec "$@"

In *.service file in section [Service]

ExecStartPre=/bin/bash -l -c 'echo "$OPTS_COMMON">/tmp/options.debug'
  • Didn't work for me. The file has no content. – Max Leske Apr 25 '20 at 10:42
  • 1
    the single ' quotes around the command prevent the variable substitution by bash. Try it with the ' and " positions swapped. bash -l -c "echo '$OPTS_COMMON'>/tmp/options.debug" instead. Alternatively, use " throughout but escape the internal pair. bash -l -c "echo \"$OPTS_COMMON\">/tmp/options.debug" – user207998 Apr 29 '20 at 13:38
  • Or something like : "echo $OPTS_COMMON | tee /tmp/options.debug" – irdroid3 Dec 19 '20 at 21:41

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.