11

I'm really new in django. I need to run a bash script when I push a button in html, and I need to do it with Django Framework, because I used it to build my web. I'd be grateful if anybody could help me

Edit: I have added my template and my views for being more helpful. In the 'nuevaCancion' template, I use 2 views.

<body>
 
 {% block cabecera %}
 <br><br><br>
 <center>
 <h2> <kbd>Nueva Cancion</kbd> </h2>
 </center>
 {% endblock %}
 
 {% block contenido %}

  <br><br>
  <div class="container">
      <form id='formulario' method='post' {% if formulario.is_multipart %} enctype="multipart/form-data" {% endif %} action=''>
    {% csrf_token %}
       <center>
    <table>{{formulario}}</table>
          <br><br>
          <p><input type='submit' class="btn btn-success btn-lg" value='Añadir'/>
     <a href="/ListadoCanciones/" type="input" class="btn btn-danger btn-lg">Cancelar</a></p>
    </center>
       </form>
     <br>
 </div>
 <center>
  <form action="" method="POST">
      {% csrf_token %}
      <button type="submit" class="btn btn-warning btn-lg">Call</button>
  </form>
 </center>
 {% endblock %}

</body>

Views.py

def index(request):
    if request.POST:
    subprocess.call('/home/josema/parser.sh')

    return render(request,'nuevaCancion.html',{})

parser.sh

#! /bin/sh
python text4midiALLMilisecs.py tiger.mid
Josema_23
  • 306
  • 1
  • 2
  • 13

5 Answers5

16

You can do this with empty form.

In your template make a empty form

# index.html
<form action="{% url 'run_sh' %}" method="POST">
    {% csrf_token %}
    <button type="submit">Call</button>
</form>

Add url for your form

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^run-sh/$', views.index, name='run_sh')
]

Now in your views.py you need to call the bash.sh script from the view that returns your template

import subprocess

def index(request):
    if request.POST:
        # give the absolute path to your `text4midiAllMilisecs.py`
        # and for `tiger.mid`
        # subprocess.call(['python', '/path/to/text4midiALLMilisecs.py', '/path/to/tiger.mid'])

        subprocess.call('/home/user/test.sh')

    return render(request,'index.html',{})

My test.sh is in the home directory. Be sure that the first line of bash.sh have sh executable and also have right permission. You can give the permissions like this chmod u+rx bash.sh.

My test.sh example

#!/bin/sh
echo 'hello'

File permision ls ~

-rwxrw-r--   1 test test    10 Jul  4 19:54  hello.sh*
Rounak
  • 806
  • 7
  • 16
Druta Ruslan
  • 7,171
  • 2
  • 28
  • 38
  • I'm trying what you say, but I think I'm missing something in my code because it doesn't work, where could I show my script and what I've done? Also, do I have to add some url or it is not needed? – Josema_23 Jul 04 '18 at 18:06
  • I have added them yet :) – Josema_23 Jul 04 '18 at 18:20
  • you have two forms, and you say the you use two `views` function for one template, try to add new `url` and add this `url` to `form action` – Druta Ruslan Jul 04 '18 at 18:27
  • i update my answer, i added the urls and add `action` to `form` – Druta Ruslan Jul 04 '18 at 18:31
  • your `bash.sh` file contains only this line of code ? `python text4midiALLMilisecs.py tiger.mid` ? – Druta Ruslan Jul 04 '18 at 18:44
  • Yes, It only has that line. text4allmilisecs.py is the file where I proccess some Code. Also I'd like to pasa tiger.mid like an argument, I mean, something generic so I can pass the file I would like. Sorry if my explanation is not as good as It should be – Josema_23 Jul 04 '18 at 18:50
  • i update my answer, you can call directly `python text4midiALLMilisecs.py tiger.mid` in `subprocess` for this one you don't need `bash.sh` file – Druta Ruslan Jul 04 '18 at 18:58
  • So I should put text4allMilisecs instead of test.sh un the view? – Josema_23 Jul 04 '18 at 19:23
  • yes but put the full path to your `text4midiALLMilisecs.py` and full path for your `tiger.mid` for example if the files are in `/home/josema/text4midiALLMilisecs.py` and `/home/josema/tiger.mid` you need to use something like this `subprocess.call(['python', '/home/josema/text4midiALLMilisecs.py', '/home/josema/tiger.mid'])` – Druta Ruslan Jul 04 '18 at 19:36
  • Thanks so much. I'll try It. I'll Mark as the right answer if It works when I try! – Josema_23 Jul 04 '18 at 19:55
  • if you will do all right it will work, because i try it and it works – Druta Ruslan Jul 04 '18 at 20:00
  • I'm disturbing again, sorry. I'm doing something wrong, because I import path in the urls.py, and I get the error that cannot import name path, but I followed everything you said me exactly. – Josema_23 Jul 05 '18 at 17:01
  • what version of the django do you have? – Druta Ruslan Jul 05 '18 at 17:17
  • I have the 1.11 version of django, and 2.7.12 version of python – Josema_23 Jul 05 '18 at 17:23
  • Thank you so much! You saved me :) – Josema_23 Jul 05 '18 at 17:31
  • Permission part was crucial to my problem, should have guessed it, but I'm quiet new to scripting so fully overlooked it. Thanks – almost a beginner Nov 13 '18 at 08:34
2

You can use python module subprocess in your view.


import subprocess

def your_view(request):

    subprocess.call('your_script.sh')


Muhtar
  • 33
  • 4
2

You can refer my blog for detailed explanation >>

http://www.easyaslinux.com/tutorials/devops/how-to-run-execute-any-script-python-perl-ruby-bash-etc-from-django-views/

I would suggest you to use Popen method of Subprocess module. Your shell script can be executed as system command with Subprocess.

Here is a little help.

Your views.py should look like this.

from subprocess import Popen, PIPE, STDOUT
from django.http import HttpResponse

def main_function(request):
    if request.method == 'POST':
            command = ["bash","your_script_path.sh"]
            try:
                    process = Popen(command, stdout=PIPE, stderr=STDOUT)
                    output = process.stdout.read()
                    exitstatus = process.poll()
                    if (exitstatus==0):
                            result = {"status": "Success", "output":str(output)}
                    else:
                            result = {"status": "Failed", "output":str(output)}

            except Exception as e:
                    result =  {"status": "failed", "output":str(e)}

            html = "<html><body>Script status: %s \n Output: %s</body></html>" %(result['status'],result['output'])
            return HttpResponse(html)

In this example, stderr and stdout of the script is saved in variable 'output', And exit code of the script is saved in variable 'exitstatus'.

Configure your urls.py to call the view function "main_function".

url(r'^the_url_to_run_the_script$', main_function)

Now you can run the script by calling http://server_url/the_url_to_run_the_script

Nijil
  • 356
  • 3
  • 9
1

Do it with Python:

With Subprocess:

import subprocess
proc = subprocess.Popen("ls -l", stdout=subprocess.PIPE)
output, err = proc.communicate()
print output

Or with os module:

import os
os.system('ls -l')
Shameer Kashif
  • 424
  • 3
  • 16
0

From Python 3.5 onwards, subprocess.run() is the recommended approach

As per the doc;

The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.

The run() function was added in Python 3.5; if you need to retain compatibility with older versions, see the Older high-level API section.

As in this example,

import subprocess

def index(request):
    if request.POST:
        subprocess.run(['/home/josema/parser.sh'])

    return render(request,'nuevaCancion.html',{})
Anupam
  • 14,950
  • 19
  • 67
  • 94