Python 中如何执行一个外部程序或调用系统命令?

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

4200726 次浏览
import osos.system("your command")

请注意,这是危险的,因为命令没有被清理。我把它留给你去谷歌搜索'os'和'sys'模块上的相关留档。有一堆函数(exec*和spawn*)会做类似的事情。

import oscmd = 'ls -al'os.system(cmd)

如果您想返回命令的结果,您可以使用#0。然而,自2.6版本以来,这已被弃用,而支持子进程模块,其他答案已经很好地覆盖了。

使用标准库中的#0模块:

import subprocesssubprocess.run(["ls", "-l"])

#0#1的优点是它更灵活(你可以得到#2#3“真实”状态码、更好的错误处理等)。

甚至留档#0建议使用subprocess

subprocess模块为生成新进程和检索其结果提供了更强大的工具;使用该模块比使用此功能更可取。请参阅#0留档中的用子进程模块替换旧函数部分以获取一些有用的食谱。

在Python 3.4及更早版本上,使用subprocess.call而不是.run

subprocess.call(["ls", "-l"])

我建议使用子进程模块而不是os.system,因为它为您执行shell转义,因此更安全。

subprocess.call(['ping', 'localhost'])

使用子进程

…或者一个非常简单的命令:

import osos.system('cat testfile')

os.system可以,但有点过时了。它也不是很安全。相反,尝试subprocesssubprocess不直接调用sh,因此比os.system更安全。

获取更多信息这里

调用外部程序的方法总结,包括它们的优点和缺点:

  1. #0将命令和参数传递给系统的shell。这很好,因为您实际上可以以这种方式一次运行多个命令并设置管道和输入/输出重定向。例如:

    os.system("some_command < input_file | another_command > output_file")

    然而,虽然这很方便,但您必须手动处理shell字符(例如空格等)的转义。另一方面,这也允许您运行简单的shell命令而不是实际的外部程序的命令。

  2. #0将做与os.system相同的事情,只是它为您提供了一个类似文件的对象,您可以使用该对象来访问该进程的标准输入/输出。popen还有另外3种变体,它们对i/o的处理方式略有不同。如果您将所有内容作为字符串传递,那么您的命令将被传递到shell;如果您将它们作为列表传递,那么您无需担心任何转义。示例:

    print(os.popen("ls -l").read())
  3. #0。这是作为os.popen的替代品,但由于非常全面,它的缺点是稍微复杂一些。例如,你会说:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

    而不是

    print os.popen("echo Hello World").read()

    但是将所有选项放在一个统一的类中而不是4个不同的popen函数中是很好的。参见留档

  4. #0。这基本上就像Popen类一样,接受所有相同的参数,但它只是等待命令完成并为您提供返回代码。例如:

    return_code = subprocess.call("echo Hello World", shell=True)
  5. #0。仅限Python 3.5+。与上述类似,但更灵活,并在命令执行完成时返回一个#1对象。

  6. os.forkos.execos.spawn与C语言类似,但我不建议直接使用它们。

subprocess模块应该是您使用的。

最后,请注意,对于所有将最终命令作为字符串传递给shell执行的方法,您有责任对其进行转义。存在严重的安全隐患如果您传递的字符串的任何部分不能完全信任。例如,如果用户正在输入字符串的某些/任何部分。如果您不确定,请仅将这些方法与常量一起使用。为了给你一个暗示,请考虑以下代码:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

假设用户输入了“my mama didnt love me && rm -rf /”,这可能会擦除整个文件系统。

典型实现:

import subprocess
p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)for line in p.stdout.readlines():print line,retval = p.wait()

您可以自由地使用管道中的stdout数据。事实上,您可以简单地省略这些参数(stdout=stderr=),它的行为就像os.system()一样。

这里还有一个以前没有提到的区别。

subprocess.Popen将<命令>作为子进程执行。在我的情况下,我需要执行需要与另一个程序通信的文件 。

我尝试了子进程,执行成功。但是无法与 通信。当我从终端运行时,一切都正常。

更多:(注意:kread的行为与其他应用程序不同。如果您使用Firefox尝试以下操作,结果将不相同。)

如果您尝试os.system("kwrite"),程序流会冻结,直到用户关闭kread。为了克服这个问题,我尝试了os.system(konsole -e kwrite)。这次程序继续流动,但kread成为控制台的子进程。

任何人都可以在不作为子进程的情况下运行kread(即在系统监视器中,它必须出现在树的最左边)。

关于从调用进程中分离子进程的一些提示(在后台启动子进程)。

假设您想从CGI脚本开始一个长任务。也就是说,子进程的生命周期应该比CGI脚本执行进程长。

子进程模块留档的经典示例是:

import subprocessimport sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here

这里的想法是,您不希望在调用子进程行中等待longtask.py完成。但不清楚示例中的“这里有更多代码”行之后会发生什么。

我的目标平台是FreeBSD,但开发是在Windows上进行的,所以我首先在Windows上遇到了这个问题。

在Windows(Windows XP)上,父进程在longtask.py完成工作之前不会完成。这不是你在CGI脚本中想要的。这个问题不是Python特有的;在PHP社区中,问题是一样的。

解决方案是将DETACHED_PROCESS进程创建标志传递给Windows API中的底层CreateProcess函数。如果你碰巧安装了pywin32,你可以从win32process模块导入标志,否则你应该自己定义它:

DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],creationflags=DETACHED_PROCESS).pid

/*UPD 2015.10.27@eryksun在下面的注释中指出,语义正确的标志是CREATE_NEW_CONSOLE(0x00000010)*/

在FreeBSD上,我们还有另一个问题:当父进程完成时,它也完成了子进程。这也不是你在CGI脚本中想要的。一些实验表明,问题似乎在于共享sys.stdout.工作解决方案如下:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

我没有检查过其他平台上的代码,也不知道FreeBSD上这种行为的原因。如果有人知道,请分享你的想法。在Python中启动后台进程的谷歌搜索还没有提供任何线索。

也检查一下“p的”Python库。

它允许对外部程序/命令进行交互式控制,甚至是ssh、ftp、telnet等。

child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')

如果您不想测试返回值,subprocess.check_call很方便。它会在任何错误上引发异常。

如果您需要正在调用的命令的输出,然后你可以使用subprocess.check_output(Python 2.7+)。

>>> subprocess.check_output(["ls", "-l", "/dev/null"])'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

还要注意shell参数。

如果shell为True,则指定的命令将通过shell执行。如果您主要将Python用于它在大多数系统shell上提供的增强控制流,并且仍然希望方便地访问其他shell功能,例如shell管道、文件名通配符、环境变量扩展和~扩展到用户的主目录,这可能很有用。但是,请注意,Python本身提供了许多类似shell的功能的实现(特别是globfnmatchos.walk()os.path.expandvars()os.path.expanduser()shutil)。

我总是使用fabric来表示这样的事情:

from fabric.operations import localresult = local('ls', capture=True)print "Content:/n%s" % (result, )

但这似乎是一个很好的工具:#0(Python子进程接口)

看一个例子:

from sh import vgdisplayprint vgdisplay()print vgdisplay('-v')print vgdisplay(v=True)

os.system不允许您存储结果,因此如果您想将结果存储在某个列表或其他内容中,则subprocess.call有效。

您可以使用Popen,然后您可以检查过程的状态:

from subprocess import Popen
proc = Popen(['ls', '-l'])if proc.poll() is None:proc.kill()

检查子进程

运行任何命令并获取结果的最简单方法:

from commands import getstatusoutput
try:return getstatusoutput("ls -ltr")except Exception, e:return None

这就是我运行命令的方式这段代码几乎包含了你所需要的一切

from subprocess import Popen, PIPEcmd = "ls -l ~/"p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)out, err = p.communicate()print "Return code: ", p.returncodeprint out.rstrip(), err.rstrip()

更新时间:

如果您的代码不需要保持与早期Python版本的兼容性,则推荐使用subprocess.run方法。它更加一致,并且提供了与Enoe类似的易用性。(管道不是那么简单。请参阅这个问题是如何。)

这里有一些来自留档的例子。

运行一个进程:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture outputCompletedProcess(args=['ls', '-l'], returncode=0)

运行失败时引发:

>>> subprocess.run("exit 1", shell=True, check=True)Traceback (most recent call last):...subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

捕获输出:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

原答复:

我建议尝试特使。它是子进程的包装器,它反过来旨在取代旧的模块和函数。特使是人类的子进程。

的自述文件的示例用法:

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)
>>> r.status_code129>>> r.std_out'usage: git config [options]'>>> r.std_err''

管周围的东西:

>>> r = envoy.run('uptime | pbcopy')
>>> r.command'pbcopy'>>> r.status_code0
>>> r.history[<Response 'uptime'>]

与标准库

使用子进程模块(Python 3):

import subprocesssubprocess.run(['ls', '-l'])

这是推荐的标准方法。然而,更复杂的任务(管道、输出、输入等)构造和编写起来可能很乏味。

注意Python版本:如果你还在使用Python 2,subprocess.call

ProTip:shlex.split可以帮助您解析runcall和其他subprocess函数的命令,以防您不想(或您不能!)以列表的形式提供它们:

import shleximport subprocesssubprocess.run(shlex.split('ls -l'))

与外部依赖

如果你不介意外部依赖,使用

from plumbum.cmd import ifconfigprint(ifconfig['wlan0']())

它是最好的subprocess包装器。它是跨平台的,即它适用于Windows和类Unix系统。按pip install plumbum安装。

另一个流行的库是sh

from sh import ifconfigprint(ifconfig('wlan0'))

但是,sh放弃了对Windows的支持,所以它不像以前那么棒了。按pip install sh安装。

在Python中运行外部命令有很多不同的方法,他们都有自己的优点和缺点。

我和我的同事一直在写Python系统管理工具,所以我们需要运行很多外部命令,有时你希望它们阻塞或异步运行,超时,每秒更新等等。

也有不同的方法来处理返回代码和错误,您可能想要解析输出,并提供新的输入(以期望的风格)。或者您需要重定向标准输入标准输出标准误差以在不同的tty中运行(例如,使用GNU屏幕时)。

所以你可能需要编写很多外部命令的包装器。所以这是我们编写的一个Python模块,它可以处理几乎任何你想要的东西,如果不是,它非常灵活,所以你可以很容易地扩展它:

https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py

它不是独立工作的,需要我们的一些其他工具,并且多年来获得了很多专业功能,所以它可能不是你的替代品,但它可以给你很多关于Python内部如何运行命令的信息,以及如何处理某些情况的想法。

2015年更新:Python 3.5添加了subprocess.run,它比subprocess. Popen更容易使用。我推荐。

>>> subprocess.run(["ls", "-l"])  # doesn't capture outputCompletedProcess(args=['ls', '-l'], returncode=0)
>>> subprocess.run("exit 1", shell=True, check=True)Traceback (most recent call last):...subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
>>> subprocess.run(["ls", "-l", "/dev/null"], capture_output=True)CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n', stderr=b'')

只是为了补充讨论,如果您使用Python控制台,您可以从IPython调用外部命令。在IPython提示符中,您可以通过前缀“!”调用shell命令。您还可以将Python代码与shell组合,并将shell脚本的输出分配给Python变量。

例如:

In [9]: mylist = !ls
In [10]: mylistOut[10]:['file1','file2','file3',]

经过一番研究,我有以下代码,它对我来说非常有效。它基本上实时打印标准输出和标准错误。

stdout_result = 1stderr_result = 1

def stdout_thread(pipe):global stdout_resultwhile True:out = pipe.stdout.read(1)stdout_result = pipe.poll()if out == '' and stdout_result is not None:break
if out != '':sys.stdout.write(out)sys.stdout.flush()

def stderr_thread(pipe):global stderr_resultwhile True:err = pipe.stderr.read(1)stderr_result = pipe.poll()if err == '' and stderr_result is not None:break
if err != '':sys.stdout.write(err)sys.stdout.flush()

def exec_command(command, cwd=None):if cwd is not None:print '[' + ' '.join(command) + '] in ' + cwdelse:print '[' + ' '.join(command) + ']'
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))
err_thread.start()out_thread.start()
out_thread.join()err_thread.join()
return stdout_result + stderr_result

使用subprocess.call

from subprocess import call
# Using listcall(["echo", "Hello", "world"])
# Single string argument varies across platforms so better split itcall("echo Hello world".split(" "))

我倾向于将子进程shlex一起使用(处理引用字符串的转义):

>>> import subprocess, shlex>>> command = 'ls -l "/your/path/with spaces/"'>>> call_params = shlex.split(command)>>> print call_params["ls", "-l", "/your/path/with spaces/"]>>> subprocess.call(call_params)

我为此写了一个库,shell.py

目前它基本上是popen和shlex的包装器。它还支持管道命令,因此您可以在Python中更轻松地链接命令。所以你可以做以下事情:

ex('echo hello shell.py') | "awk '{print $2}'"

一个简单的方法是使用os模块

import osos.system('ls')

或者,您也可以使用子进程模块:

import subprocesssubprocess.check_call('ls')

如果您希望将结果存储在变量中,请尝试:

import subprocessr = subprocess.check_output('ls')

也有Plumbum

>>> from plumbum import local>>> ls = local["ls"]>>> lsLocalCommand(<LocalPath /bin/ls>)>>> ls()u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'>>> notepad = local["c:\\windows\\notepad.exe"]>>> notepad()                                   # Notepad window pops upu''                                             # Notepad window is closed by user, command returns

用途:

import os
cmd = 'ls -al'
os.system(cmd)

os-此模块提供了一种使用操作系统相关功能的可移植方式。

对于更多的os函数,这里是留档。

使用subprocess Python模块的Popen函数是运行Linux命令的最简单方法。在这种情况下,Popen.communicate()函数将输出您的命令。例如

import subprocess
..process = subprocess.Popen(..)   # Pass command and arguments to the functionstdout, stderr = process.communicate()   # Get command output and error..

这是我的两分钱:在我看来,这是处理外部命令时的最佳实践…

这些是执行方法的返回值…

pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")

这是执行方法…

def execute(cmdArray,workingDir):
stdout = ''stderr = ''
try:try:process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)except OSError:return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']
for line in iter(process.stdout.readline, b''):
try:echoLine = line.decode("utf-8")except:echoLine = str(line)
stdout += echoLine
for line in iter(process.stderr.readline, b''):
try:echoLine = line.decode("utf-8")except:echoLine = str(line)
stderr += echoLine
except (KeyboardInterrupt,SystemExit) as err:return [False,'',str(err)]
process.stdout.close()
returnCode = process.wait()if returnCode != 0 or stderr != '':return [False, stdout, stderr]else:return [True, stdout, stderr]

对于Python 3.5+,建议您使用从子进程模块运行函数。这返回一个CompletedProcess对象,您可以从中轻松获取输出和返回代码。

from subprocess import PIPE, run
command = ['echo', 'hello']result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)print(result.returncode, result.stdout, result.stderr)

我会推荐以下方法'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 Falsereturn dict({'output': out, 'error': err, 'status': ret})#end

在Windows中,您只需导入subprocess模块并通过调用subprocess.Popen()subprocess.Popen().communicate()subprocess.Popen().wait()运行外部命令,如下所示:

# Python script to run a command lineimport subprocess
def execute(cmd):"""Purpose  : To execute a command and return exit statusArgument : cmd - command to executeReturn   : exit_code"""process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)(result, error) = process.communicate()
rc = process.wait()
if rc != 0:print "Error: failed to execute command:", cmdprint errorreturn result# def
command = "tasklist | grep python"print "This process detail: \n", execute(command)

输出:

This process detail:python.exe                     604 RDP-Tcp#0                  4      5,660 K

用途:

import subprocess
p = subprocess.Popen("df -h", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]print p.split("\n")

它提供了很好的输出,更容易使用:

['Filesystem      Size  Used Avail Use% Mounted on','/dev/sda6        32G   21G   11G  67% /','none            4.0K     0  4.0K   0% /sys/fs/cgroup','udev            1.9G  4.0K  1.9G   1% /dev','tmpfs           387M  1.4M  386M   1% /run','none            5.0M     0  5.0M   0% /run/lock','none            1.9G   58M  1.9G   3% /run/shm','none            100M   32K  100M   1% /run/user','/dev/sda5       340G  222G  100G  69% /home','']

OpenStack中子获取网络ID:

#!/usr/bin/pythonimport osnetid = "nova net-list | awk '/ External / { print $2 }'"temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */networkId = temp.rstrip()print(networkId)

输出nova网表

+--------------------------------------+------------+------+| ID                                   | Label      | CIDR |+--------------------------------------+------------+------+| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None || 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None || 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None || 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |+--------------------------------------+------------+------+

输出打印网络地址

27a74fcd-37c0-4789-9414-9531b7e3f126

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

  • 例如:

如果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 oscmd = " ".join(exename,parameters)os.popen(cmd)

这里调用一个外部命令并返回或打印命令的输出:

Python子进程check_output

使用参数运行命令并将其输出作为字节字符串返回。

import subprocessproc = subprocess.check_output('ipconfig /all')print proc

有许多不同的库允许您使用Python调用外部命令。对于每个库,我都给出了描述并展示了调用外部命令的示例。我用作示例的命令是ls -l(列出所有文件)。如果您想了解更多关于我列出的任何库的信息,并链接了它们的每个留档。

来源

这些是所有的图书馆

希望这能帮助你决定使用哪个库:)

子进程

子进程允许您调用外部命令并将它们连接到它们的输入/输出/错误管道(stdin、stdout和stderr)。子进程是运行命令的默认选择,但有时其他模块更好。

subprocess.run(["ls", "-l"]) # Run commandsubprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any outputsubprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

os

OS用于“操作系统相关功能”。它也可以用来调用os.systemos.popen的外部命令(注意:还有一个subprocess.popen)。os将始终运行shell,对于不需要或不知道如何使用subprocess.run的人来说是一个简单的替代方案。

os.system("ls -l") # Run commandos.popen("ls -l").read() # This will run the command and return any output

sh

sh是一个子进程接口,可让您像调用函数一样调用程序。如果您想多次运行命令,这很有用。

sh.ls("-l") # Run command normallyls_cmd = sh.Command("ls") # Save command as a variablels_cmd() # Run command as if it were a function

Plumbum是一个用于“类脚本”Python程序的库。您可以像sh中的函数一样调用程序。如果您想在没有shell的情况下运行管道,Plumbum很有用。

ls_cmd = plumbum.local("ls -l") # Get commandls_cmd() # Run command

p的

您可以生成子应用程序、控制它们并在它们的输出中找到模式。这是对Unix上需要tty的命令进行子处理的更好替代方案。

pexpect.run("ls -l") # Run command as normalchild = pexpect.spawn('scp foo user@example.com:.') # Spawns child applicationchild.expect('Password:') # When this is the outputchild.sendline('mypassword')

织物

Fabric是一个Python 2.5和2.7库。它允许您执行本地和远程shell命令。Fabric是在安全shell(SSH)中运行命令的简单替代方案

fabric.operations.local('ls -l') # Run command as normalfabric.operations.local('ls -l', capture = True) # Run command and receive output

特使

特使被称为“人类的子进程”。它被用作subprocess模块的方便包装器。

r = envoy.run("ls -l") # Run commandr.std_out # Get output

命令

commands包含os.popen的包装函数,但它已从Python 3中删除,因为subprocess是更好的选择。

在Linux下,如果您想调用将独立执行的外部命令(将在Python脚本终止后继续运行),您可以使用简单的队列作为任务假脱机程序命令。

使用任务假脱机程序的示例:

import osos.system('ts <your-command>')

关于任务假脱机程序(ts)的注释:

  1. 您可以使用以下命令设置要运行的并发进程数(“插槽”):

    ts -S <number-of-slots>

  2. 安装ts不需要管理员权限。您可以使用简单的make从源代码下载并编译它,将其添加到您的路径中,就完成了。

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

简单,使用subprocess.run,它返回一个CompletedProcess对象:

>>> from subprocess import run>>> from shlex import split>>> completed_process = run(split('python --version'))Python 3.8.8>>> completed_processCompletedProcess(args=['python', '--version'], returncode=0)

run需要一个词法解析的shell参数列表——这是你在shell中键入的内容,用空格分隔,但不是空格引用的地方,所以使用一个专门的函数split来分割你在shell中键入的内容)

为啥?

从Python 3.5开始,留档建议subprocess.run

调用子进程的推荐方法是对它可以处理的所有用例使用run()函数。对于更高级的用例,可以直接使用底层Popen接口。

下面是一个最简单的用法示例——它完全按照要求执行:

>>> from subprocess import run>>> from shlex import split>>> completed_process = run(split('python --version'))Python 3.8.8>>> completed_processCompletedProcess(args=['python', '--version'], returncode=0)

run等待命令成功完成,然后返回一个CompletedProcess对象。它可能会引发TimeoutExpired(如果您给它一个timeout=参数)或CalledProcessError(如果它失败并且您传递check=True)。

正如您可能从上面的示例中推断的那样,默认情况下,stdout和stderr都会通过管道传输到您自己的stdout和stderr。

我们可以检查返回的对象并查看给定的命令和返回代码:

>>> completed_process.args['python', '--version']>>> completed_process.returncode0

捕获输出

如果要捕获输出,可以将subprocess.PIPE传递给相应的stderrstdout

>>> from subprocess import PIPE>>> completed_process = run(shlex.split('python --version'), stdout=PIPE, stderr=PIPE)>>> completed_process.stdoutb'Python 3.8.8\n'>>> completed_process.stderrb''

这些各自的属性返回字节。

传递命令列表

人们可能很容易从手动提供命令字符串(如问题所建议的)转向提供以编程方式构建的字符串。不要以编程方式构建字符串。这是一个潜在的安全问题。最好假设您不信任输入。

>>> import textwrap>>> args = ['python', textwrap.__file__]>>> cp = run(args, stdout=subprocess.PIPE)>>> cp.stdoutb'Hello there.\n  This is indented.\n'

注意,只有args应该在位置上传递。

完整签名

这是源代码中的实际签名,如help(run)所示:

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargskwargs被赋予Popen构造函数。input可以是一串字节(或Unicode,如果指定编码或universal_newlines=True),它将通过管道传输到子进程的标准输入。

留档比我更好地描述了timeout=check=True

超时参数传递给Popen.communicate()。如果超时过期,子进程将被杀死并等待。这个TimeoutExpired异常将在子进程完成后重新引发结束。

如果check为true,并且进程以非零退出代码退出,则将引发CalledProcessError异常。该属性异常保存参数、退出代码以及stdout和stderr,如果被抓了

这个check=True的例子比我能想到的更好:

>>> subprocess.run("exit 1", shell=True, check=True)Traceback (most recent call last):...subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

扩展签名

这是一个扩展的签名,如留档中所示:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None,shell=False, cwd=None, timeout=None, check=False, encoding=None,errors=None)

请注意,这表明只有args列表应该按位置传递。因此将剩余参数作为关键字参数传递。

Popen

什么时候使用Popen?我很难仅根据参数找到用例。然而,直接使用Popen会让您访问其方法,包括poll、'send_signal'、'终止'和'等待'。

这是的来源中给出的Popen签名。我认为这是对信息的最精确的封装(与help(Popen)相反):

def __init__(self, args, bufsize=-1, executable=None,stdin=None, stdout=None, stderr=None,preexec_fn=None, close_fds=True,shell=False, cwd=None, env=None, universal_newlines=None,startupinfo=None, creationflags=0,restore_signals=True, start_new_session=False,pass_fds=(), *, user=None, group=None, extra_groups=None,encoding=None, errors=None, text=None, umask=-1, pipesize=-1):

更多信息是#0留档

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None,stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None,env=None, universal_newlines=None, startupinfo=None, creationflags=0,restore_signals=True, start_new_session=False, pass_fds=(), *, group=None,extra_groups=None, user=None, umask=-1, encoding=None, errors=None,text=None)

在新进程中执行子程序。在POSIX上,类使用os.execvp()的行为来执行子程序。该类使用Windows CreateProcess()函数。Popen如下。

理解Popen上剩下的留档将留给读者练习。

我写了一个包装器来处理错误和重定向输出和其他东西。

import shleximport psutilimport subprocess
def call_cmd(cmd, stdout=sys.stdout, quiet=False, shell=False, raise_exceptions=True, use_shlex=True, timeout=None):"""Exec command by command line like 'ln -ls "/var/log"'"""if not quiet:print("Run %s", str(cmd))if use_shlex and isinstance(cmd, (str, unicode)):cmd = shlex.split(cmd)if timeout is None:process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)retcode = process.wait()else:process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)p = psutil.Process(process.pid)finish, alive = psutil.wait_procs([p], timeout)if len(alive) > 0:ps = p.children()ps.insert(0, p)print('waiting for timeout again due to child process check')finish, alive = psutil.wait_procs(ps, 0)if len(alive) > 0:print('process {} will be killed'.format([p.pid for p in alive]))for p in alive:p.kill()if raise_exceptions:print('External program timeout at {} {}'.format(timeout, cmd))raise CalledProcessTimeout(1, cmd)retcode = process.wait()if retcode and raise_exceptions:print("External program failed %s", str(cmd))raise subprocess.CalledProcessError(retcode, cmd)

你可以这样称呼它:

cmd = 'ln -ls "/var/log"'stdout = 'out.txt'call_cmd(cmd, stdout)

例如(Linux):

import subprocesssubprocess.run('mkdir test.dir', shell=True)

这将在当前目录中创建test.dir。请注意,这也有效:

import subprocesssubprocess.call('mkdir test.dir', shell=True)

使用os.system的等效代码是:

import osos.system('mkdir test.dir')

最佳实践是使用子进程而不是os,. run优于. call。所有你需要知道的子进程是这里。另外,请注意,所有Python留档都可以从这里下载。我下载了打包为. zip的PDF。我提到这一点是因为tutorial.pdf中有一个很好的os模块概述(第81页)。此外,它是Python程序员的权威资源。

通常,我使用以下函数来执行外部命令,这对于长时间运行的进程尤其方便。下面的方法尾处理输出正在运行并返回输出,如果进程失败,则返回提出一个例外

如果该过程是使用进程上的投票()方法完成的,则会出现。

import subprocess,sys
def exec_long_running_proc(command, args):cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args))print(cmd)process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Poll process for new output until finishedwhile True:nextline = process.stdout.readline().decode('UTF-8')if nextline == '' and process.poll() is not None:breaksys.stdout.write(nextline)sys.stdout.flush()
output = process.communicate()[0]exitCode = process.returncode
if (exitCode == 0):return outputelse:raise Exception(command, exitCode, output)

你可以像这样调用它:

exec_long_running_proc(command = "hive", args=["-f", hql_path])

在Python中调用外部命令

调用外部命令的一种简单方法是使用os.system(...)。这个函数返回命令的退出值。但缺点是我们不会得到stdout和stderr。

ret = os.system('some_cmd.sh')if ret != 0 :print 'some_cmd.sh execution returned failure'

在后台调用Python中的外部命令

subprocess.Popen为运行外部命令提供了更大的灵活性,而不是使用os.system。我们可以在后台启动命令并等待它完成。之后我们可以获得标准输出和标准错误。

proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)print 'waiting for ' + str(proc.pid)proc.wait()print 'some_cmd.sh execution finished'(out, err) = proc.communicate()print 'some_cmd.sh output : ' + out

在后台调用Python中长时间运行的外部命令并在一段时间后停止

我们甚至可以使用subprocess.Popen在后台启动一个长时间运行的进程,并在任务完成后的某个时间杀死它。

proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)# Do something else# Now some_long_run_cmd.sh exeuction is no longer needed, so kill itos.system('kill -15 ' + str(proc.pid))print 'Output : ' proc.communicate()[0]

可以这么简单:

import oscmd = "your command"os.system(cmd)

如果您需要从Python笔记本(如Jupyter、Zeppelin、数据库或Google Cloud Datalab)调用shell命令,您可以使用!前缀。

例如,

!ls -ilF

调用是一个Python(2.7和3.4+)任务执行工具和库。它为运行shell命令提供了一个干净、高级的API:

>>> from invoke import run>>> cmd = "pip install -r requirements.txt">>> result = run(cmd, hide=True, warn=True)>>> print(result.ok)True>>> print(result.stdout.splitlines()[-1])Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1

我写了一个小库来帮助这个用例:

https://pypi.org/project/citizenshell/

它可以安装使用

pip install citizenshell

然后使用如下:

from citizenshell import shassert sh("echo Hello World") == "Hello World"

您可以将标准输出与标准错误分开,并提取退出代码,如下所示:

result = sh(">&2 echo error && echo output && exit 13")assert result.stdout() == ["output"]assert result.stderr() == ["error"]assert result.exit_code() == 13

很酷的是,在开始处理输出之前,您不必等待底层shell退出:

for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False)print ">>>", line + "!"

由于等待=False,将打印可用的行

>>> It is 14:24:52!>>> It is 14:24:53!>>> It is 14:24:54!>>> It is 14:24:55!

更多示例可以在https://github.com/meuter/citizenshell中找到

对于在Python 3.5+中使用subprocess,下面的技巧对我Linux:

import subprocess
# subprocess.run() returns a completed process object that can be inspectedc = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)print(c.stdout.decode('utf-8'))

留档中所述,PIPE值是字节序列,应该考虑正确显示它们的解码。对于更高版本的Python,text=Trueencoding='utf-8'被添加到#3的kwargs中。

上述代码的输出是:

total 113M-rwxr-xr-x  1 farzad farzad  307 Jan 15  2018 vpnscript-rwxrwxr-x  1 farzad farzad  204 Jan 15  2018 exdrwxrwxr-x  4 farzad farzad 4.0K Jan 22  2018 scripts.... # Some other lines

如果您在命令中使用用户输入没有,您可以使用:

from os import getcwdfrom subprocess import check_outputfrom 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,因此您可以使用管道和类似的shellsh('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通过shell=True显式调用,则为应用程序有责任确保所有空格和适当引用元字符以避免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

苏丹是一个用于此目的的最新软件包。它提供了一些关于管理用户权限和添加有用错误消息的细节。

from sultan.api import Sultan
with Sultan.load(sudo=True, hostname="myserver.com") as sultan:sultan.yum("install -y tree").run()

如果您正在编写Python外壳脚本并在系统上安装了IPython,则可以使用ang前缀在IPython中运行shell命令:

!lsfilelist = !ls

python3.5+

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

在线试用

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

在线试用

os.popen()是执行命令的最简单和最安全的方式。您可以执行在命令行上运行的任何命令。此外,您还可以使用os.popen().read()捕获命令的输出

你可以这样做:

import osoutput = os.popen('Your Command Here').read()print (output)

列出当前目录中所有文件的示例:

import osoutput = os.popen('ls').read()print (output)# Outputs list of files in the directory

大多数情况下:

在大多数情况下,像这样的一小段代码就是您所需要的

import subprocessimport shlex
source = "test.txt"destination = "test_copy.txt"
base = "cp {source} {destination}'"cmd = base.format(source=source, destination=destination)subprocess.check_call(shlex.split(cmd))

它是干净和简单

subprocess.check_call使用参数运行命令并等待命令完成。

shlex.split使用类似shell的语法拆分字符串cmd

其他案例:

如果这对某些特定命令不起作用,很可能您遇到了 命令行解释器问题。操作系统选择了不适合您的程序类型的默认程序,或者在系统可执行路径上找不到合适的程序。

示例:

在Unix系统上使用重定向运算符

input_1 = "input_1.txt"input_2 = "input_2.txt"output = "merged.txt"base_command = "/bin/bash -c 'cat {input} >> {output}'"
base_command.format(input_1, output=output)subprocess.check_call(shlex.split(base_command))
base_command.format(input_2, output=output)subprocess.check_call(shlex.split(base_command))

正如Python的禅中所说:显式比显式更好隐式

因此,如果使用Python>=3.6函数,它看起来像这样:

import subprocessimport shlex
def run_command(cmd_interpreter: str, command: str) -> None:base_command = f"{cmd_interpreter} -c '{command}'"subprocess.check_call(shlex.split(base_command)

来自Python的呼吁和外部命令有多种方式。有一些函数和模块带有很好的辅助函数,可以让它变得非常容易。但推荐的是subprocess模块。

import subprocess as ss.call(["command.exe", "..."])

调用函数将启动外部进程,传递一些命令行参数并等待它完成。当它完成时,您继续执行。打电话函数中的参数通过列表传递。列表中的第一个参数是通常以可执行文件形式出现的命令,列表中的后续参数是您想要传递的任何参数。

如果你以前在Windows中从命令行调用过进程,你会意识到你经常需要引用参数。你需要在它周围加上引号。如果有空格,那么就有反斜杠,并且有一些复杂的规则,但是你可以通过使用subprocess模块在Python中避免很多,因为它是一个列表,每个项目都是不同的,python可以为你正确引用。

最后,在列表之后,有许多可选参数,其中一个是shell,如果您将shell设置为true,那么您的命令将运行,就像您在命令提示符下输入一样。

s.call(["command.exe", "..."], shell=True)

这使您可以访问管道等功能,您可以重定向到文件,您可以在一件事中调用多个命令。

还有一件事,如果您的脚本依赖于成功的进程,那么您想检查结果,并且可以使用check调用辅助函数检查结果。

s.check_call(...)

它和调用函数完全一样,它接受相同的参数,接受相同的列表,你可以传入任何额外的参数,但它会等待函数完成。如果函数的退出代码是除零之外的任何东西,它将通过python脚本中的异常。

最后,如果您想要更严格的控制Popen构造函数,它也来自subprocess模块。它也采用与incall&check_call函数相同的参数,但它返回一个表示正在运行的进程的对象。

p=s.Popen("...")

它不会等待正在运行的进程完成,也不会立即抛出任何异常,但它会给你一个对象,让你做一些事情,比如等待它完成,让你与它通信,你可以重定向标准输入,如果你想在其他地方显示输出,标准输出等等。

我在Python 3.6+中使用它:

import subprocessdef execute(cmd):"""Purpose  : To execute a command and return exit statusArgument : cmd - command to executeReturn   : result, exit_code"""process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)(result, error) = process.communicate()rc = process.wait()if rc != 0:print ("Error: failed to execute command: ", cmd)print (error.rstrip().decode("utf-8"))return result.rstrip().decode("utf-8"), serror.rstrip().decode("utf-8")# def

从2018年6月27日发布的Python 3.7.0(https://docs.python.org/3/whatsnew/3.7.html开始,你可以用最强大而同样简单的方式实现你想要的结果。这个答案打算以简短的方式向你展示各种选项的基本总结。关于深入的答案,请参见其他答案。


太长别读2021

os.system(...)的最大优点是它的简单性。subprocess更好,仍然易于使用,尤其是在python3.5中。

import subprocesssubprocess.run("ls -a", shell=True)

注:这是您问题的确切答案-运行命令

就像一个贝壳


首选方式

如果可能,删除shell开销并直接运行命令(需要列表)。

import subprocesssubprocess.run(["help"])subprocess.run(["ls", "-a"])

在列表中传递程序参数。不要为包含空格的参数包含#0-转义。


高级用例

检查输出

以下代码不言自明:

import subprocessresult = subprocess.run(["ls", "-a"], capture_output=True, text=True)if "stackoverflow-logo.png" in result.stdout:print("You're a fan!")else:print("You're not a fan?")

result.stdout是所有正常的程序输出排除错误。读取result.stderr以获取它们。

capture_output=True-开启捕捉。否则result.stderrresult.stdout将是None。可从python3.7获得。

text=True-python3.7中添加的便利参数,它将接收到的二进制数据转换为您可以轻松使用的Python字符串。

检查返回码

if result.returncode == 127: print("The program failed for some weird reason")elif result.returncode == 0: print("The program succeeded")else: print("The program failed unexpectedly")

如果你只是想检查程序是否成功(返回代码==0)并抛出Exception,有一个更方便的函数:

result.check_returncode()

但它是Python,所以有一个更方便的参数check会自动为你做同样的事情:

result = subprocess.run(..., check=True)

stderr应该在stdout里面

您可能希望将所有程序输出都包含在标准输出中,甚至是错误。要做到这一点,请运行

result = subprocess.run(..., stderr=subprocess.STDOUT)

result.stderr将是Noneresult.stdout将包含所有内容。

使用shell=False和参数字符串

shell=False需要列表个参数。但是,您可以使用shlex自行拆分参数字符串。

import subprocessimport shlexsubprocess.run(shlex.split("ls -a"))

就这样了。

常见问题

当你遇到这个问题时,你很有可能刚刚开始使用Python。让我们看看一些常见问题。

FileNotFoundError:[Errno 2]没有这样的文件或目录:'ls-a':'ls-a'

您正在运行一个没有shell=True的子进程。要么使用列表(["ls", "-a"]),要么设置shell=True

TypeError:[…]无类型[…]

检查您是否设置了capture_output=True

TypeError:需要一个类似字节的对象,而不是[…]

您总是从您的程序中收到字节结果。如果您想像正常字符串一样使用它,请设置text=True

命令“[…]”返回非零退出状态1。

您的命令未成功运行。您可以禁用返回码检查或检查实际程序的有效性。

TypeError:init()得到了一个意想不到的关键字参数[…]

您可能使用的是3.7.0之前的Python版本;将其更新到可用的最新版本。否则,在这篇Stack Overflow文章中还有其他答案,向您展示了更旧的替代解决方案。

您可以使用子进程模块中的<强>教皇n运行任何命令。

from subprocess import Popen

首先,使用您要运行的所有参数创建一个命令对象。例如,在下面的片段中,Gunicorm命令对象已经由所有参数形成:

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())

然后这个命令对象与<强>教皇n一起使用来实例化一个进程:

process = Popen(cmd, shell=True)

这个过程也可以根据任何信号终止,使用下面的代码行:

Popen.terminate(process)

你可以等到上面命令的执行完成:

process.wait()

这里有很多答案,但没有一个能满足我所有的需求。

  • 我需要运行命令并捕获输出退出码
  • 我需要超时执行的程序和退出,如果达到超时,和杀死所有子进程
  • 我需要它在WindowsXP和更高版本,Cygwin和Linux中工作。在Python 2和3中。

所以我创建了这个:

def _run(command, timeout_s=False, shell=False):### run a process, capture the output and wait for it to finish. if timeout is specified then Kill the subprocess and its children when the timeout is reached (if parent did not detach)## usage: _run(arg1, arg2, arg3)# arg1: command + arguments. Always pass a string; the function will split it when needed# arg2: (optional) timeout in seconds before force killing# arg3: (optional) shell usage. default shell=False## return: a list containing: exit code, output, and if timeout was reached or not
# - Tested on Python 2 and 3 on Windows XP, Windows 7, Cygwin and Linux.# - preexec_fn=os.setsid (py2) is equivalent to start_new_session (py3) (works on Linux only), in Windows and Cygwin we use TASKKILL# - we use stderr=subprocess.STDOUT to merge standard error and standard outputimport sys, subprocess, os, signal, shlex, time
def _runPY3(command, timeout_s=None, shell=False):# py3.3+ because: timeout was added to communicate() in py3.3.new_session=Falseif sys.platform.startswith('linux'): new_session=Truep = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, start_new_session=new_session, shell=shell)
try:out = p.communicate(timeout=timeout_s)[0].decode('utf-8')is_timeout_reached = Falseexcept subprocess.TimeoutExpired:print('Timeout reached: Killing the whole process group...')killAll(p.pid)out = p.communicate()[0].decode('utf-8')is_timeout_reached = Truereturn p.returncode, out, is_timeout_reached
def _runPY2(command, timeout_s=0, shell=False):preexec=Noneif sys.platform.startswith('linux'): preexec=os.setsidp = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=preexec, shell=shell)
start_time = time.time()is_timeout_reached = Falsewhile timeout_s and p.poll() == None:if time.time()-start_time >= timeout_s:print('Timeout reached: Killing the whole process group...')killAll(p.pid)is_timeout_reached = Truebreaktime.sleep(1)out = p.communicate()[0].decode('utf-8')return p.returncode, out, is_timeout_reached
def killAll(ParentPid):if sys.platform.startswith('linux'):os.killpg(os.getpgid(ParentPid), signal.SIGTERM)elif sys.platform.startswith('cygwin'):# subprocess.Popen(shlex.split('bash -c "TASKKILL /F /PID $(</proc/{pid}/winpid) /T"'.format(pid=ParentPid)))winpid=int(open("/proc/{pid}/winpid".format(pid=ParentPid)).read())subprocess.Popen(['TASKKILL', '/F', '/PID', str(winpid), '/T'])elif sys.platform.startswith('win32'):subprocess.Popen(['TASKKILL', '/F', '/PID', str(ParentPid), '/T'])
# - In Windows, we never need to split the command, but in Cygwin and Linux we need to split if shell=False (default), shlex will split the command for usif shell==False and (sys.platform.startswith('cygwin') or sys.platform.startswith('linux')):command=shlex.split(command)
if sys.version_info >= (3, 3): # py3.3+if timeout_s==False:returnCode, output, is_timeout_reached = _runPY3(command, timeout_s=None, shell=shell)else:returnCode, output, is_timeout_reached = _runPY3(command, timeout_s=timeout_s, shell=shell)else:  # Python 2 and up to 3.2if timeout_s==False:returnCode, output, is_timeout_reached = _runPY2(command, timeout_s=0, shell=shell)else:returnCode, output, is_timeout_reached = _runPY2(command, timeout_s=timeout_s, shell=shell)
return returnCode, output, is_timeout_reached

然后像这样使用它:

始终将命令作为一个字符串传递(这更容易)。您不需要拆分它;函数会在需要时拆分它。

如果您的命令在您的shell中工作,它将使用此函数,因此首先在shell中测试您的命令cmd/Bash。

所以我们可以像这样使用timeout:

a=_run('cmd /c echo 11111 & echo 22222 & calc',3)for i in a[1].splitlines(): print(i)

或者没有超时:

b=_run('cmd /c echo 11111 & echo 22222 & calc')

更多示例:

b=_run('''wmic nic where 'NetConnectionID="Local Area Connection"' get NetConnectionStatus /value''')print(b)
c=_run('cmd /C netsh interface ip show address "Local Area Connection"')print(c)
d=_run('printf "<%s>\n" "{foo}"')print(d)

您还可以指定shell=True,但在大多数情况下使用此函数是无用的。我更喜欢选择自己想要的shell,但如果您也需要它,请在这里选择:

# windowse=_run('echo 11111 & echo 22222 & calc',3, shell=True)print(e)# Cygwin/Linux:f=_run('printf "<%s>\n" "{foo}"', shell=True)print(f)

为什么我没有使用更简单的新方法subprocess.run()

  • 因为Python3.7+支持它,但Windows XP中最后一个支持的Python版本是3.4.4
  • 并且由于此函数的timeout参数在Windows中无用,因此它不会杀死执行命令的子进程。
  • 如果您使用capture_output+timeout参数,如果有子进程仍在运行,它将挂起。并且它在Windows中仍然被破坏,其中问题31447仍然开放

您可以尝试使用os.system()来运行外部命令。

示例:

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

在示例中,脚本导入os并尝试运行os.system()中列出的命令。如果命令失败,那么它将打印“错误运行命令”,而脚本不会因错误而停止。

是的,就是这么简单!