在Python中运行bash脚本

162

我有一个问题与以下代码:

callBash.py:

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

sleep.sh:

sleep 10

我希望在10秒后打印出"end"(我知道这是一个愚蠢的例子,我可以在Python中使用sleep,但这个简单的sleep.sh文件只是一个测试)。


我也尝试了使用"$!bin/bash; sleep 10; "。 - user1638145
2
这个问题试图询问的问题不太清楚,但是这个问题可能应该保留,因为它已经积累了一个历史性的杂烩,其中包含了更多或少的好猜测作为答案。可能还要搜索您特定的错误,并/或阅读类似于https://dev59.com/cG855IYBdhLWcg3wlVca的相关问题。 - tripleee
7个回答

123
使 sleep.sh 可执行并在参数列表中添加“shell=True”(如先前回答中建议的)即可正常运行。根据搜索路径,您可能还需要添加“./”或其他适当的路径。(例如,将“sleep.sh”更改为“./sleep.sh”。)
在类 Unix 系统(如 Linux)下,如果 Bash 脚本的第一行是 Shell 路径(例如“#!/bin/bash”),则不需要“shell=True”参数。

1
仅作为额外信息,shell=True是不被推荐的 - 文档,因为它会使您的程序容易受到Shell注入攻击。 - user20068036

73

如果 sleep.sh 文件有 #!/bin/sh 这样的shebang,并且有适当的文件权限 -- 可以运行 chmod u+rx sleep.sh 确保文件权限正确,并且该文件在 $PATH 中,那么你的代码应该可以正常工作:

import subprocess

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

如果脚本不在路径中,请指定它的完整路径,例如,如果它在当前工作目录中:

from subprocess import call

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

如果脚本没有shebang,则需要指定shell=True

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

如果脚本没有可执行权限,并且您无法更改它,例如通过运行os.chmod('sleep.sh', 0o755),则可以将脚本作为文本文件读取,并将字符串传递给subprocess模块:

with open('sleep.sh', 'rb') as file:
    script = file.read()
rc = call(script, shell=True)

谢谢你的工作。有没有不使用 import 的方法?我想在我的作业中使用你的代码,但是我们不能在 py 文件中使用 import。 - c0d3x27
@c0d3x27 在Python中运行shell命令的常规方法是使用subprocess模块。虽然有一些在Python中不需要显式导入就可以完成的方法,但这些都是肮脏的黑客技巧,只用于逃离沙盒环境(除非你正在学习Python安全性,否则这不太可能是你的作业)。 - jfs
是的,确认这可行,无需使用shell=True,实际上可以使用#!/usr/bin/env zsh代替,因为这是在macos上使用zsh。 - JL Peyret

46

如果有人正在寻找如何带参数调用脚本

import subprocess

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

在传递参数之前,记得将参数转换为字符串,使用 str(arg)。

这可以用来传递任意数量的参数:

subprocess.check_call("./script.ksh %s %s %s" % (arg1, str(arg2), arg3), shell=True)

10
我建议使用列表作为参数,例如 subprocess.check_call(["./script.ksh", arg1, arg2, arg3], shell=True) 这种方式对我来说更清晰明了,而且你不需要关心格式。 - Nerxis

37

实际上,您只需要添加 shell=True 参数:

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

但是请注意 -

警告:如果与不受信任的输入组合使用,则使用shell=True调用系统shell可能会导致安全风险。有关详细信息,请参见常用参数下的警告。

来源


1
如果sleep.sh不在PATH中,它将无法工作。如果它路径中,并且具有正确的shebang,则不需要使用shell=True。请参见我的答案 - jfs

15
请确保sleep.sh具有执行权限,并使用shell=True运行它。
#!/usr/bin/python

import subprocess
print "start"
subprocess.call("./sleep.sh", shell=True)
print "end"

所以我错过了 shell=True。你能解释一下为什么在 sh 脚本的第一行设置 #!bin/bash 不足够吗? - user1638145
5
#!bin/bash 中的错误是缺少 /。如我在答案中所指出的,#!/bin/bash 是有效的。 - James Waldby - jwpat7

14

如果chmod无效,您还可以尝试:

import os
os.system('sh script.sh')
# you can also use bash instead of sh

3
os.system的文档特别建议使用subprocess(现在是subprocess.run())代替它。如果你无法让subprocess正常工作,那么很有可能你也会在使用os.system()时遇到问题。 - tripleee

3

因为我问如何在Python中运行bash脚本而被引导到这里,所以我添加了一个答案。如果您的脚本接受参数,则会收到错误OSError: [Errno 2] file not found。假设您的脚本接受一个休眠时间参数: subprocess.call("sleep.sh 10") 将不起作用,您必须将其作为数组传递: subprocess.call(["sleep.sh", 10])


你必须理解shell=True的实际含义,但通常最好避免使用它。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接