如何在Python中调用外部命令,就像在shell或命令提示符中键入它一样?
如何在Python中调用外部命令,就像在shell或命令提示符中键入它一样?
os.system()
来运行外部命令。import os
try:
os.system('ls')
pass
except:
print("Error running command")
pass
os
并尝试运行在 os.system()
中列出的命令。如果命令执行失败,它会打印“Error running command”,但脚本不会因此错误而停止。如果您的命令中 不 使用用户输入,您可以使用以下方法:
from os import getcwd
from subprocess import check_output
from shlex import quote
def sh(command):
return check_output(quote(command), shell=True, cwd=getcwd(), universal_newlines=True).strip()
使用它作为
branch = sh('git rev-parse --abbrev-ref HEAD')
shell=True
会启动一个 shell,因此你可以使用管道和其他 shell 相关的命令 sh('ps aux | grep python')
。这对于运行硬编码命令并处理其输出非常方便。 universal_lines=True
确保输出以字符串形式返回而不是二进制形式。
cwd=getcwd()
确保命令在与解释器相同的工作目录中运行。这对于像上面 Git 分支名称示例那样工作的 Git 命令非常方便。
一些示例:
sh('free -m').split('\n')[1].split()[1]
sh('df -m /').split('\n')[1].split()[4][0:-1]
sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])
但这对于用户输入来说并不安全,根据文档:
安全注意事项
与其他一些 popen 函数不同,该实现永远不会隐式调用系统 shell。这意味着所有字符,包括 shell 元字符,都可以安全地传递给子进程。如果通过 shell=True 显式调用 shell,则应用程序有责任确保适当引用所有空格和元字符,以避免 shell 注入漏洞。
当使用 shell=True 时,可以使用 shlex.quote() 函数来正确转义字符串中的空格和 shell 元字符,以构造 shell 命令。
即使使用了 shlex.quote()
,在使用用户输入进行 shell 命令时最好保持一些警惕。一种选择是使用硬编码命令获取一些通用输出并通过用户输入进行过滤。无论如何,使用 shell=False
可确保只执行您想要执行的进程,否则会出现 No such file or directory
错误。
此外,shell=True
会有一定的性能影响,在我的测试中似乎比默认值 shell=False
慢约 20%。
In [50]: timeit("check_output('ls -l'.split(), universal_newlines=True)", number=1000, globals=globals())
Out[50]: 2.6801227919995654
In [51]: timeit("check_output('ls -l', universal_newlines=True, shell=True)", number=1000, globals=globals())
Out[51]: 3.243950183999914
import subprocess
p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())
有很多方法可以调用命令。
如果and.exe
需要两个参数。在cmd中,我们可以这样调用sample.exe
:
and.exe 2 3
,它会在屏幕上显示5
。
如果我们使用Python脚本来调用and.exe
,我们应该这样做...
os.system(cmd,...)
os.system(("and.exe" + " " + "2" + " " + "3"))
os.popen(cmd,...)
os.popen(("and.exe" + " " + "2" + " " + "3"))
subprocess.Popen(cmd,...)
subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))
这太难了,所以我们可以用空格将cmd连接起来:
import os
cmd = " ".join(exename,parameters)
os.popen(cmd)
os.popen
,甚至不应再提及。subprocess
示例应该将参数作为列表传递,而不是用空格连接它们。 - tripleee使用Python的subprocess
模块中的Popen
函数是运行Linux命令最简单的方法。其中,Popen.communicate()
函数会给出你运行命令的输出结果。例如:
import subprocess
..
process = subprocess.Popen(..) # Pass command and arguments to the function
stdout, stderr = process.communicate() # Get command output and error
..
Popen()
的低级控制,否则应优先选择subprocess.check_call()
和相关函数。在最近的Python版本中,首选工具是subprocess.run()
。 - tripleeeos.popen()
是执行命令最简单、最安全的方式。你可以执行在命令行上运行的任何命令。此外,你也可以使用os.popen().read()
捕获命令的输出。
你可以这样做:
import os
output = os.popen('Your Command Here').read()
print (output)
import os
output = os.popen('ls').read()
print (output)
# Outputs list of files in the directory
有多种方法可以从Python中调用外部命令。有一些函数和模块提供了非常好的辅助功能,可以使它变得非常容易。但是,所有建议的方法中最好的是使用subprocess
模块。
import subprocess as s
s.call(["command.exe", "..."])
调用函数将启动外部进程,传递一些命令行参数并等待其完成。当它完成后,您可以继续执行。在调用函数中,参数通过列表传递。列表中的第一个参数通常是可执行文件形式的命令,列表中的后续参数是您想要传递的任何内容。
如果以前在Windows命令行中调用过进程,则应该知道您经常需要引用参数。您需要在其周围放置引号标记。如果有空格,那么就有反斜杠和一些复杂的规则,但是您可以通过使用subprocess
模块来避免大量这样的问题,因为它是一个列表,每个项目都被认为是不同的,并且Python可以为您正确地引用。
最后,在列表之后,有许多可选参数之一是shell,如果将shell设置为true,则您的命令将像在命令提示符处输入一样运行。
s.call(["command.exe", "..."], shell=True)
这使您可以访问像管道这样的功能,可以将输出重定向到文件中,还可以在一个事务中调用多个命令。
另外,如果您的脚本依赖于进程成功,则需要检查结果,并且可以使用check调用助手函数进行检查。
s.check_call(...)
这个函数与调用函数完全相同,它接受相同的参数、列表,可以传入任何额外的参数,但它将等待函数完成。如果函数的退出码不为零,则在Python脚本中会引发异常。
最后,如果您想要更严格的控制,可以使用subprocess
模块中的Popen
构造函数。它也接受与incall和check_call函数相同的参数,但返回一个表示正在运行的进程的对象。
p=s.Popen("...")
它不会等待运行的进程完成,也不会立即抛出任何异常,但它会给您一个对象,让您可以执行像等待进程完成、与进程通信、重定向标准输入、标准输出等等操作。
def run (cmd):
print "+ DEBUG exec({0})".format(cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
(out, err) = p.communicate()
ret = p.wait()
out = filter(None, out.split('\n'))
err = filter(None, err.split('\n'))
ret = True if ret == 0 else False
return dict({'output': out, 'error': err, 'status': ret})
#end
subprocess.run()
的东西。当不是绝对必要时,应特别避免使用shell=True
。 - tripleee#end
有什么用处? - Peter Mortensenfrom subprocess import Popen
首先,创建一个包含您要运行的所有参数的命令对象。例如,在下面的代码片段中,使用所有参数形成了gunicorn命令对象:
cmd = (
"gunicorn "
"-c gunicorn_conf.py "
"-w {workers} "
"--timeout {timeout} "
"-b {address}:{port} "
"--limit-request-line 0 "
"--limit-request-field_size 0 "
"--log-level debug "
"--max-requests {max_requests} "
"manage:app").format(**locals())
process = Popen(cmd, shell=True)
可以根据任何信号使用以下代码行终止此过程:
Popen.terminate(process)
您可以等待上述命令执行完成:
process.wait()
Python 3.5+
import subprocess
p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())