1

I wrote a shell script using python and it successfully run by command bash download_R1.sh on my terminal.

I wanted to test if subprocess can do the same thing in python because I would like to integrate a pipeline in python script. Here is the subprocess part of my code:

downR1 = subprocess.call('./download_R1.sh')

It failed to run the script with following error message:

Error message:
PermissionError: [Errno 13] Permission denied: './download_R1.sh'

Someone suggested using chmod +x to obtain authenitification of that script. But bash down.sh is working. I don't know which part goes wrong.

Any advice?

tomasz
  • 39
  • 5

1 Answers1

1

That's the normal way the shell behaves.

You can not directly run a program or script if it not has execution privileges (+x)

But, you can instruct other program bash, python or whatever to run a file even if not has +x

foo.sh

#!/bin/bash

# If a parameter is received in the command $1, assign it to $NAME
# if not use the default "World"
NAME="${1:-World}"

echo "Hello ${NAME}"

foo.py

#!/usr/bin/env python
print "Hello World"
$ bash foo.sh
Hello World

$ bash foo.sh Person
Hello Person

$ ./foo.sh
bash: ./foo.sh: Permission denied

$ python foo.py
Hello World


$ ./foo.py
bash: ./foo.sh: Permission denied

$ chmod +x foo.sh foo.py

$ ./foo.sh
Hello World
$ ./foo.py
Hello World

In your case, if you want to run the program with subprocess but not giving execution privileges to the file you must use:

subprocess.run(["bash", "download_R1.sh"])

If you need to pass arguments to the script just add more items to the list:

subprocess.run(["bash", "download_R1.sh", "argument1"])

There are several questions about using subprocess an arguments like this one.

If you prefer write you command in only one string be advised that use shell=True is not recommended. But you can use something like:

subprocess.run("bash download_R1.sh argument1".split())
Francisco Puga
  • 23,869
  • 5
  • 48
  • 64
  • OP's script is a `bash` script, so they need `subprocess.run(["bash", "download_R1.sh"])`. ... I think. – Mark Setchell Jul 01 '22 at 09:59
  • Oh, I understand now! Thank you. You are correct except `subprocess.run(["python", "download_R1.sh"])` should be `subprocess.run(["bash", "download_R1.sh"])`. May I ask one more question? In document describing `subprocess.run(args)`, it said that `The arguments used to launch the process. This may be a list or a string`. `bash download_R1.sh` is a string. But what about list? Does it mean subprocess can consecutively run shell scripts following the list, e.g. `('bash 1.sh' , 'bash 2.sh', 'bash 3.sh')`? – tomasz Jul 01 '22 at 11:01
  • After a few test, I know how args input should look like. Args receive a list composed of a seperated command, like ['bash', '1.sh'], or a string 'bash 1.sh' but only with `shell=True` to enable it, otherwise it will report FileNotFound error. Am I correct? – tomasz Jul 01 '22 at 11:30
  • Yes you can pass one long string as the full command with `shell=True` but it's not recommend https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess use `long_string.split()` with `shell=False` if needed – Francisco Puga Jul 02 '22 at 08:37