145

I have a problem with the following code:

callBash.py:

import subprocess
print "start"
subprocess.call("sleep.sh")
print "end"

sleep.sh:

sleep 10

I want the "end" to be printed after 10s. (I know that this is a dumb example, I could simply sleep within python, but this simple sleep.sh file was just as a test)

user1638145
  • 1,819
  • 2
  • 14
  • 14
  • I also tried it with "$!bin/bash; sleep 10; " – user1638145 Dec 06 '12 at 14:29
  • 1
    It is unclear what problem this questien is trying to ask about, but the question should probably remain because it has accrued a historical grab bag of more or less good guesses as answers. Probably also search for your specific error, and/or read related questions like https://stackoverflow.com/questions/4256107/running-bash-commands-in-python – tripleee Jun 02 '20 at 02:08

7 Answers7

111

Making sleep.sh executable and adding shell=True to the parameter list (as suggested in previous answers) works ok. Depending on the search path, you may also need to add ./ or some other appropriate path. (Ie, change "sleep.sh" to "./sleep.sh".)

The shell=True parameter is not needed (under a Posix system like Linux) if the first line of the bash script is a path to a shell; for example, #!/bin/bash.

James Waldby - jwpat7
  • 8,385
  • 2
  • 20
  • 37
60

If sleep.sh has the shebang #!/bin/sh and it has appropriate file permissions -- run chmod u+rx sleep.sh to make sure and it is in $PATH then your code should work as is:

import subprocess

rc = subprocess.call("sleep.sh")

If the script is not in the PATH then specify the full path to it e.g., if it is in the current working directory:

from subprocess import call

rc = call("./sleep.sh")

If the script has no shebang then you need to specify shell=True:

rc = call("./sleep.sh", shell=True)

If the script has no executable permissions and you can't change it e.g., by running os.chmod('sleep.sh', 0o755) then you could read the script as a text file and pass the string to subprocess module instead:

with open('sleep.sh', 'rb') as file:
    script = file.read()
rc = call(script, shell=True)
jfs
  • 374,366
  • 172
  • 933
  • 1,594
36

Actually, you just have to add the shell=True argument:

subprocess.call("sleep.sh", shell=True)

But beware -

Warning Invoking the system shell with shell=True can be a security hazard if combined with untrusted input. See the warning under Frequently Used Arguments for details.

source

zenpoy
  • 18,614
  • 8
  • 55
  • 87
  • 1
    It won't work if `sleep.sh` is not in the `PATH`. And if it *is* in the path and it has the correct shebang then you don't need `shell=True`. See [my answer](http://stackoverflow.com/a/22416147/4279) – jfs Mar 14 '14 at 21:37
36

If someone looking for calling a script with arguments

import subprocess

val = subprocess.check_call("./script.sh '%s'" % arg, shell=True)

Remember to convert the args to string before passing, using str(arg).

This can be used to pass as many arguments as desired:

subprocess.check_call("./script.ksh %s %s %s" % (arg1, str(arg2), arg3), shell=True)
Antonin GAVREL
  • 7,991
  • 4
  • 44
  • 60
Ponmudi VN
  • 1,333
  • 1
  • 17
  • 22
  • 6
    I recommend using list as arguments like `subprocess.check_call(["./script.ksh", arg1, arg2, arg3], shell=True)` which seems clearer to me and you do not need to care about formatting. – Nerxis Jun 03 '21 at 14:26
15

Make sure that sleep.sh has execution permissions, and run it with shell=True:

#!/usr/bin/python

import subprocess
print "start"
subprocess.call("./sleep.sh", shell=True)
print "end"
Adam Matan
  • 117,979
  • 135
  • 375
  • 532
13

If chmod is not working then you can also try:

import os
os.system('sh script.sh')
# you can also use bash instead of sh
alper
  • 2,299
  • 4
  • 36
  • 73
Harry1992
  • 427
  • 5
  • 11
  • 1
    The `os.system` documentation specifically recommends avoiding it in favor of `subprocess` (these days, `subprocess.run()`). If you can't get `subprocess` to work, chances are you'll have trouble with `os.system()` too. – tripleee Jun 02 '20 at 02:03
3

Adding an answer because I was directed here after asking how to run a bash script from python. You receive an error OSError: [Errno 2] file not found if your script takes in parameters. Lets say for instance your script took in a sleep time parameter: subprocess.call("sleep.sh 10") will not work, you must pass it as an array: subprocess.call(["sleep.sh", 10])

  • You have to understand [the actual meaning of `shell=True`](https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess) but yes, usually avoiding it is your best play. – tripleee Jun 02 '20 at 02:05