What does /bin/bash -c mean in service unit?

To make my app autorun during reboot.

sudo vi /etc/systemd/system/app.service
[Unit]
Description=app
After=network.target
[Service]
ExecStart=/usr/bin/python /usr/local/bin/app
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable app.service

Now my app autorun during reboot.
I want to make my app write all output info into /var/log/app.log.
Here is what i do.
1.sudo touch /var/log/app.log
2. to change ExecStart only.

ExecStart=/usr/bin/python /usr/local/bin/app > /var/log/app.log 2>&1

App can run but no log written into /var/log/app.log.
Root will execute the app.
It's proof here.

ps aux|grep app
root 246 0.0 3.8 56052 10056 ? Ss 00:57 0:00 /usr/bin/python /usr/local/bin/app > /var/log/app.log 2>&1

Why root has no permission to write log into /var/log/app.log?

To change ExecStart statement into

ExecStart=/bin/sh -c '/usr/bin/python /usr/local/bin/app > /var/log/app.log 2>&1' 

Problem solved.
1.Why root no permission to write log into /var/log/app.log?
2.What does /bin/bash -c mean in service unit?

1

3 Answers

It's not a matter of permissions. There is simply no shell involved in executing the ExecStart string. Only a command and the options to be passed to that command, but neither redirections nor piping nor concatening with ; nor substitution or any other shell functionality. Thus, your "redirections" are passed as options to your app (only you know how your app handles this).

You can change this by calling a shell and giving your command and redirections as command string to the shell. This is what the -c option does.

But think about why not use the services and logging as intended by systemd: By default stdout and stderr of a systemd unit are sent to syslog. You can configure it with the StandardOutput= line in your service. Have a look at man systemd.exec

NOTE: The old post was written in the context of OP's original question, before edit, so it is incomplete but in the context of what was originally was asked, it's still valid.

Updated answer:

The key issue here is that

ExecStart=/usr/bin/python /usr/local/bin/app > /var/log/app.log 2>&1

Doesn't have shell running , so your > and 2>&1 redirection won't be understood by systemd.

That's why shell is necessary around the whole command so that redirection can work. As for -c flag for shell, see the old version of the post below.


OLD POST

The -c flag in both bash and sh mean same thing: execute commands as provided within the quotes. There's no great mystery.

Your app that you're trying to run might have different meaning for -c flag, so don't assume all command-line flags are the same for all commands. Without documentation for the app, it's hard to tell what an option is supposed to do.

Potential issue here is that python interpreter will assume -c as its own command-line argument, not to the app. Probably that's the main reason your command fails.

The ExecStart=/usr/bin/python /usr/local/bin/app -c /etc/app.json should be able to process your command. I've tested it with a small script:

$ cat test_script.py
import sys
print sys.argv[1],sys.argv[0]
$ python test_script.py this is a test
this test_script.py

Better approach: a script should be made executable with sudo chmod +x /usr/local/bin/app and used by itself. The way it is written originally, with /bin/sh, then python, then calling actual script is kind of redundant. In the example of my test script that would be like so:

$ cat test_script.py
#!/usr/bin/env python
import sys
print sys.argv[1],sys.argv[0]
$ chmod +x test_script.py
$ ./test_script.py this is a test
this ./test_script.py

Beware that python refers to Python 2.7 on Ubuntu. If you need to use Python3 specifically, use /usr/bin/python3 instead. Most preferred way is for the app to have #!/usr/bin/env python or #!/usr/bin/env python3 as first line.

1

sudo vi /etc/systemd/system/app.service

[Unit]
Description=app
After=network.target
[Service]
ExecStart=/usr/bin/python /usr/local/bin/app
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target

sudo systemctl daemon-reload
sudo systemctl enable app.service

To search app's log with journal command.

sudo journalctl -u app

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

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

You Might Also Like