Adding a Shell Command Inside/Inline of a Systemd Service File

Adding a shell command inside/inline of a systemd service file

You can explicitly invoke a shell to get shell parsing.

ExecStart=/bin/bash -c '/usr/local/bin/gunicorn --workers "$(nproc --all)" --threads "$(nproc --all)" --backlog 100 --bind 10.0.0.20:5000 -m 777 abc:app'

Creating filename_$(date %Y-%m-%d) from systemd bash inline script

You'll need to escape the $ and % signs, by doubling them both in order to make this work.

As described here:

  • https://github.com/systemd/systemd/issues/2146
  • https://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines

To pass a literal dollar sign, use "$$"

ExecStart=/bin/bash -c 'echo $$(date +%%Y-%%m-%%d) >> /home/username/test_output_$$(date +%%Y-%%m-%%d).log'

Start systemd user service from Rails

I was able to solve the issue by telling the shell where to find the correct DBUS for the user. I set the environment variable XDG_RUNTIME_DIR to the location of DBUS for the user, 1001 in my case. Check echo $UID to find user id, I couldn't use this inline.

`export XDG_RUNTIME_DIR="/run/user/1001" && systemctl --user start myservice`

Thanks to D.j. Molny for the initial sign post and NeilCasey for the remainder

Systemd with multiple execStart

if Type=simple in your unit file, you can only specify one ExecStart, but you can add as many ExecStartPre, ExecStartPost, but none of this is suited for long running commands, because they are executed serially and everything one start is killed before starting the next one.

If Type=oneshot you can specify multiple ExecStart, they run serially not in parallel.

If what you want is to run multiple units in parallel, there a few things you can do:

If they differ on 1 param

You can use template units, so you create a /etc/systemd/system/foo@.service. NOTE: (the @ is important).

[Unit]
Description=script description %I

[Service]
Type=simple
ExecStart=/script.py %i
Restart=on-failure

[Install]
WantedBy=multi-user.target

And then you exec:

$ systemctl start foo@parameter1.service foo@parameter2.service

or...

Target dependencies

You can create multiple units that links to a single target:

#/etc/systemd/system/bar.target
[Unit]
Description=bar target
Requires=multi-user.target
After=multi-user.target
AllowIsolate=yes

And then you just modify you .service units to be WantedBy=bar.target like:

#/etc/systemd/system/foo@.service
[Unit]
Description=script description %I

[Service]
Type=simple
ExecStart=/script.py %i
Restart=on-failure

[Install]
WantedBy=bar.target

Then you just enable the foo services you want in parallel, and start the bar target like this:

$ systemctl daemon-reload
$ systemctl enable foo@param1.service
$ systemctl enable foo@param2.service
$ systemctl start bar.target

NOTE: that this works with any type of units not only template units.

Set environment variables from file of key/value pairs

Problem with your approach is the export in the while loop is happening in a sub shell, and those variable will not be available in current shell (parent shell of while loop).

Add export command in the file itself:

export MINIENTREGA_FECHALIMITE="2011-03-31"
export MINIENTREGA_FICHEROS="informe.txt programa.c"
export MINIENTREGA_DESTINO="./destino/entrega-prac1"

Then you need to source in the file in current shell using:

. ./conf/prac1

OR

source ./conf/prac1

Linux Script to redirect output to log file with date filename

You can use date to choose the format of the log file. Assuming YYYY-MM-DD, you can use the following. Note using '>>' to append/create the log file.

java abc.java >> "logfile.$(date +'%Y-%m-%d').log"
# Test
echo abc.java >> "logfile.$(date +'%Y-%m-%d').log"

Also note that 'java abc.java' need to be reviewed. The java command is usually invoked with class name (java abc), and not the name of a file.



Related Topics



Leave a reply



Submit