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



Question:

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?


Solution:1

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.


Solution:2

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


Solution:3

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  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »