如何执行程序或调用系统命令?

6066

如何在Python中调用外部命令,就像在shell或命令提示符中键入它一样?

66个回答

5
你可以尝试使用os.system()来运行外部命令。
示例:
import os

try:
  os.system('ls')
  pass
except:
  print("Error running command")
  pass

在这个例子中,脚本导入了 os 并尝试运行在 os.system() 中列出的命令。如果命令执行失败,它会打印“Error running command”,但脚本不会因此错误而停止。
是的,就是这么简单!

5

如果您的命令中 使用用户输入,您可以使用以下方法:

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]
  • CPU 负载: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

5
import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())

在线尝试


需要进行解释。例如,这个想法是什么,与11年前的50个答案有何不同? - Peter Mortensen
这与您几天前的答案完全相同,只是更少的细节。 - tripleee

4

有很多方法可以调用命令。

  • 例如:

如果and.exe需要两个参数。在cmd中,我们可以这样调用sample.exe: and.exe 2 3,它会在屏幕上显示5

如果我们使用Python脚本来调用and.exe,我们应该这样做...

  1. os.system(cmd,...)

    • os.system(("and.exe" + " " + "2" + " " + "3"))
  2. os.popen(cmd,...)

    • os.popen(("and.exe" + " " + "2" + " " + "3"))
  3. subprocess.Popen(cmd,...)
    • subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))

这太难了,所以我们可以用空格将cmd连接起来:

import os
cmd = " ".join(exename,parameters)
os.popen(cmd)

不应再推荐使用os.popen,甚至不应再提及。subprocess示例应该将参数作为列表传递,而不是用空格连接它们。 - tripleee

4

使用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() - tripleee

4

os.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

4

有多种方法可以从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("...")

它不会等待运行的进程完成,也不会立即抛出任何异常,但它会给您一个对象,让您可以执行像等待进程完成、与进程通信、重定向标准输入、标准输出等等操作。


3
我建议使用以下方法“run”,它将帮助我们以字典的形式获取标准输出标准错误和退出状态;调用者可以读取由“run”方法返回的字典,以了解进程的实际状态。
  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

1
这个不完全重新实现了类似于subprocess.run()的东西。当不是绝对必要时,应特别避免使用shell=True - tripleee
#end 有什么用处? - Peter Mortensen

3
你可以使用subprocess模块中的Popen命令来运行任何命令。
from 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())

然后,可以使用这个命令对象与Popen一起创建一个进程实例:
process = Popen(cmd, shell=True)

可以根据任何信号使用以下代码行终止此过程:

Popen.terminate(process)

您可以等待上述命令执行完成:

process.wait()

3

Python 3.5+

import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())

在线尝试


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