6

I wrote a Python script that executes some bash scripts like this:

cmd = subprocess.Popen(['bash', 'script.sh'])

That way it executes the script although I didn't set execute permissions with chmod. I can also write in the terminal bash script.sh and it works the same. I know scripts can be executed by prepending dot slash ./ to them like this ./script.sh.

So, which way should I use in my Python script? Why?

  • 3
    Whatever you do: stick to 1 method and put it inside a procedure/function so you limit the place where you use it to as few as possible (1 ;-) ). That way whatever you feel like maintenance is as easy as possible. – Rinzwind Mar 19 '17 at 6:49
  • It's probably best to use path/script, because that allows you to switch to another language besides Bash scripting later. – Chai T. Rex Mar 19 '17 at 7:42
  • You should probably rephrase it as, "What is the best practice..." to get it reopened. – juniorRubyist Jun 9 '17 at 21:07
10

First, regarding the dot in ./script.sh, this indicates that script.sh can be found in the working directory, it means something like "look for script.sh here, in this directory". This is known as dot slash, and it is well explained here.

I see three options:

  1. If you intend to restrict the file to only run if it is in the user's current working directory when he runs your Python script, then use the dot slash. However, this doesn't seem like the best idea: it will lead to exceptions most of the time.

  2. If you intend to restrict your shell script to run only if it is in the same directory as your Python script, then you would need to find out your Python script's directory and prefix it to the name of your script.

  3. If you intend to place your shell script elsewhere in your PATH, don't use the dot slash.

Now, sending "bash" as an argument to the Popen constructor seems more like a matter of preference. If you don't want to send it as an argument, then you will need to add a shebang to the shell script, e.g. #!/bin/bash, and you will need to add execute permissions to it. These are perfectly acceptable things to do.

One benefit of doing it this way is if later one changes the shell interpreter, it won't be necessary to modify every single call to that script in who knows how many Python scripts.

And one can just call the script like:

cmd = subprocess.call('script.sh')
# or
cmd = subprocess.call(sdir + 'script.sh')
# Where sdir stands for the script's directory,
# which you would need to find before, as in option #2.

Notes:

Even if your script runs without a shebang normally (in which case it almost certainly gets executed by dash and not by bash on Debian based distros), when calling it from python like this, it will fail and raise an OSError exception with errno 8 (errno.ENOEXEC).

If it's really necessary, use Popen.

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.