从Python调用外部命令


Answers:


4691

查看标准库中的子流程模块:

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

的优势subprocess主场迎战system的是,它是更灵活(你可以得到的stdoutstderr,“真正”的状态代码,更好的错误处理,等等)。

官方文件建议subprocess在替代模块os.system()

subprocess模块提供了更强大的功能来生成新流程并检索其结果。使用该模块优于使用此功能[ os.system()]。

与子模块更换旧的功能中部分subprocess文件可能有一些有益的食谱。

对于3.5之前的Python版本,请使用call

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

有没有办法使用变量替换?IE我尝试echo $PATH通过使用来做call(["echo", "$PATH"]),但是它只是回显文字字符串,$PATH而不是进行任何替换。我知道我可以获取PATH环境变量,但是我想知道是否有一种简单的方法来使命令的行为完全像在bash中执行过的一样。
凯文·惠勒2015年

@KevinWheeler您必须使用shell=True它才能工作。
SethMMorton 2015年

38
@KevinWheeler请勿使用shell=True,为此,Python随附了os.path.expandvars。您可以写:os.path.expandvars("$PATH")。@SethMMorton,请重新考虑您的评论-> 为什么不使用shell = True
Murmel,2015年

会阻塞吗?即,如果我想在一个for循环中运行多个命令,如何在不阻塞我的python脚本的情况下执行呢?我不在乎命令的输出,我只想运行许多命令。
查理·帕克

4
如果您想从带有参数的命令中创建一个列表,该列表可以与subprocesswhen 一起使用shell=False,则可以shlex.split通过一种简单的方法来执行此操作docs.python.org/2/library/shlex.html#shlex.split
Daniel F

2982

下面总结了调用外部程序的方法以及每种方法的优缺点:

  1. os.system("some_command with args")将命令和参数传递到系统的外壳程序。很好,因为您实际上可以以这种方式一次运行多个命令,并设置管道和输入/输出重定向。例如:

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

但是,尽管这样做很方便,但您必须手动处理转义字符(例如空格等)的外壳字符。另一方面,这也使您可以运行仅是外壳程序命令而非实际上是外部程序的命令。请参阅文档

  1. stream = os.popen("some_command with args")os.system除了会为您提供类似于文件的对象之外,您可以使用该对象来访问该过程的标准输入/输出,它的作用与之相同。Popen还有其他3种变体,它们对I / O的处理略有不同。如果您将所有内容都作为字符串传递,那么您的命令将传递到外壳程序;如果将它们作为列表传递,则无需担心转义任何内容。请参阅文档

  2. 模块的Popensubprocess。它旨在替代它,os.popen但缺点是由于太全面而使它稍微复杂一些。例如,您会说:

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

    代替:

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

    但是将所有选项都放在一个统一的类中而不是4个不同的popen函数是一件好事。请参阅文档

  3. call来自subprocess模块的功能。基本上就像Popen类一样,并接受所有相同的参数,但是它只是等待命令完成并提供返回代码。例如:

    return_code = subprocess.call("echo Hello World", shell=True)  

    请参阅文档

  4. 如果您使用的是Python 3.5或更高版本,则可以使用新subprocess.run函数,该函数与上面的代码非常相似,但是更加灵活,并CompletedProcess在命令完成执行后返回一个对象。

  5. os模块还具有您在C程序中拥有的所有fork / exec / spawn函数,但是我不建议直接使用它们。

subprocess模块可能是您所使用的模块。

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

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

并想象用户输入了“我的妈妈不爱我&& rm -rf /”这可能会擦除整个文件系统的信息。


22
好的答案/解释。这个答案如何证明本文所述的Python座右铭? fastcompany.com/3026446/… “从风格上讲,Perl和Python有不同的理念。Perl最著名的座右铭是:“有不止一种方法可以做到这一点。” Python被设计为有一种显而易见的方法可以做到这一点。另一种方法!在Perl中,我只知道两种执行命令的方法-使用反-或open
吉恩(Jean)

12
如果使用Python 3.5+,请使用subprocess.run()docs.python.org/3.5/library/subprocess.html#subprocess.run
凤凰城

4
通常需要知道的是子进程的STDOUT和STDERR会做什么,因为如果在某些(非常常见)的条件下忽略它们,最终子进程将发出系统调用以写入STDOUT(也是STDERR?)。它将超过操作系统为该进程提供的输出缓冲区,并且操作系统将使其阻塞,直到某些进程从该缓冲区读取为止。因此,使用当前推荐的方法,“这默认情况下不会捕获stdout或stderr”的subprocess.run(..)确切含义是什么意味着?那subprocess.check_output(..)和STDERR呢?
Evgeni Sergeev'6

2
@Pitto是的,但这不是示例所执行的。注意echo传递给Popen?的字符串的前面。因此完整的命令将是echo my mama didnt love me && rm -rf /
克里斯·阿恩特

6
可以说这是错误的方法。大多数人只需要subprocess.run()或年长的兄弟姐妹subprocess.check_call()等。对于这些不足的情况,请参见subprocess.Popen()os.popen()也许根本不应该提及,甚至在“破解自己的fork / exec / spawn代码”之后也不应提及。
三人房

357

典型的实现:

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


44
.readlines()一次读取所有行,即阻塞直到子进程退出(关闭管道末端)。要实时阅读(如果没有缓冲问题),您可以:for line in iter(p.stdout.readline, ''): print line,
jfs 2012年

1
您能否详细说明“如果没有缓冲问题”是什么意思?如果该进程确实阻塞,则子进程调用也将阻塞。我的原始示例也可能发生同样的情况。关于缓冲还有什么可能发生?
EmmEff 2012年

15
子进程可能会在非交互模式下使用块缓冲而不是行缓冲,因此p.stdout.readline()(注意:s结尾处为否)在子进程填充其缓冲区之前不会看到任何数据。如果孩子没有产生太多数据,那么输出将不是实时的。请参阅Q中的第二个原因:为什么不只使用管道(popen())?此答案中提供一些解决方法(pexpect,pty,stdbuf)
jfs

4
仅当您要实时输出并且不适用于在收到所有数据之前不打印任何内容的代码时,缓冲问题才重要
jfs 2012年

3
这个时间很合适,但是Popen对于简单的任务,我们不再建议。这也不必要地指定shell=True。尝试subprocess.run()答案之一。
Tripleee '18

230

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

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

子流程模块文档中的经典示例是:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

这里的想法是,您不想在long任务.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中启动后台进程尚未阐明。


我注意到在pydev + eclipse中开发py2exe应用程序时可能会出现“怪癖”。我能够说出主脚本没有分离,因为eclipse的输出窗口没有终止。即使脚本执行完成,它仍在等待返回。但是,当我尝试编译为py2exe可执行文件时,会发生预期的行为(以分离的方式运行进程,然后退出)。我不确定,但是可执行文件名称不再在进程列表中。这适用于所有方法(os.system(“ start *”),带有os.P_DETACH的os.spawnl,subprocs等)
maranas 2010年

1
您可能还需要CREATE_NEW_PROCESS_GROUP标志。即使直接子项已终止,也
jfs 2012年

5
以下内容是错误的:“ [o] n windows(win xp),在longtask.py完成工作之前,父进程将不会完成”。父级将正常退出,但是控制台窗口(conhost.exe实例)仅在最后一个附加进程退出时关闭,并且子级可能继承了父级的控制台。设置DETACHED_PROCESScreationflags通过防止孩子继承或创建一个控制台避免这一点。如果您想要一个新的控制台,请使用CREATE_NEW_CONSOLE(0x00000010)。
Eryk Sun 2015年

1
我并不是说作为一个独立的进程执行是不正确的。就是说,您可能需要将标准句柄设置为文件,管道,或者os.devnull因为某些控制台程序退出而出现错误。当您希望子进程与父进程同时与用户交互时,请创建一个新的控制台。尝试在单个窗口中同时执行这两个操作会令人困惑。
Eryk Sun

1
是否有与操作系统无关的方法来使进程在后台运行?
查理·帕克

151
import os
os.system("your command")

请注意,这很危险,因为未清除命令。我留给你去谷歌搜索有关“操作系统”和“系统”模块的相关文档。有很多函数(exec *和spawn *)将执行类似的操作。


6
我不知道十年前的意思(检查日期!),但是如果我不得不猜测,那就是没有完成验证。
nimish

1
现在,这应该指向subprocess一种更加通用和可移植的解决方案。当然,运行外部命令本质上是不可移植的(您必须确保该命令在您需要支持的每种体系结构上都可用),并且将用户输入作为外部命令传递本质上是不安全的。
Tripleee '18

1
请注意此人的时间戳:“正确”答案的投票是40倍,是答案#1。
nimish

一个对我有效的运行NodeJS的解决方案。
Nikolay Shindarov,

147

我建议你使用模块,而不是使用os.system因为它没有外壳逃避你,因此更加安全。

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

如果您想从带有参数的命令中创建一个列表,该列表可以与subprocesswhen 一起使用shell=False,则可以shlex.split通过一种简单的方法来执行此操作docs.python.org/2/library/shlex.html#shlex.split(根据docs docs.python.org/2/library/subprocess.html#popen-constructor),这是推荐的方法)
Daniel F

6
这是不正确的:“ 它确实为您提供了转义功能,因此更加安全 ”。子进程不会进行外壳转义,子进程不会通过外壳传递您的命令,因此无需进行外壳转义。
Lie Ryan

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

如果要返回命令的结果,可以使用os.popen。但是,自2.6版以来,不推荐使用此方法,而支持subprocess模块,其他答案已经很好地涵盖了这一点。


10

您还可以使用os.system调用保存结果,因为它的工作方式类似于UNIX shell本身,例如os.system('ls -l> test2.txt')
Stefan Gruenwald,2017年

97

有很多不同的库,可让您使用Python调用外部命令。对于每个库,我都进行了描述并显示了调用外部命令的示例。我用作示例的命令是ls -l(列出所有文件)。如果您想了解有关任何库的更多信息,我已列出并链接了每个库的文档。

资料来源:

这些都是库:

希望这可以帮助您决定使用哪个库:)

子过程

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

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

操作系统

os用于“取决于操作系统的功能”。它也可以用于通过os.system和调用外部命令os.popen(注意:还有一个subprocess.popen)。os将始终运行该shell,对于不需要或不知道如何使用的人来说,它是一个简单的选择subprocess.run

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

SH

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

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

plumbum是用于“类似脚本”的Python程序的库。您可以像中的函数那样调用程序sh。如果您要在没有外壳的情况下运行管道,则Plumbum很有用。

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

期待

pexpect使您可以生成子应用程序,对其进行控制并在其输出中找到模式。对于在Unix上需要tty的命令,这是子过程的更好选择。

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

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

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

使者

特使被称为“人类子过程”。它用作subprocess模块周围的便利包装。

r = envoy.run("ls -l") # Run command
r.std_out # get output

命令

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

该编辑基于JF Sebastian的评论。


74

我总是用fabric这样的东西:

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

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

看一个例子:

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

73

还要检查“ pexpect” Python库。

它允许交互式控制外部程序/命令,甚至包括ssh,ftp,telnet等。您可以键入以下内容:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

70

与标准库

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

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

这是推荐的标准方式。但是,构造和编写更复杂的任务(管道,输出,输入等)可能很繁琐。

关于Python版本的注意事项:如果您仍在使用Python 2,subprocess.call的工作方式与此类似。

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

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

具有外部依赖性

如果您不介意外部依赖性,请使用plumbum

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

这是最好的subprocess包装纸。它是跨平台的,即可以在Windows和类似Unix的系统上运行。由安装pip install plumbum

另一个受欢迎的图书馆是sh

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

但是,已sh放弃Windows支持,因此它不像以前那样出色。由安装pip install sh


69

如果您需要从您所呼叫的命令的输出,那么你可以使用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用于大多数系统外壳程序提供的增强控制流,并且仍希望方便地访问其他外壳程序功能(例如外壳程序管道,文件名通配符,环境变量扩展以及〜扩展到用户的家),则这可能很有用。目录。但是请注意,Python本身提供的实现多壳状的功能(尤其是globfnmatchos.walk()os.path.expandvars()os.path.expanduser(),和shutil)。


1
请注意,这check_output需要列表而不是字符串。如果您不依靠加引号的空格来使您的通话有效,则最简单,最易读的方法是subprocess.check_output("ls -l /dev/null".split())
布鲁诺·布罗诺斯基

56

这就是我运行命令的方式。这段代码包含了您非常需要的所有内容

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

3
我认为,如果它可以提高可读性,则对于硬编码命令是可以接受的。
亚当·马坦

54

更新:

subprocess.run如果您的代码不需要保持与早期Python版本的兼容性,则从python 3.5开始,建议使用此方法。它更加一致,并且提供与Envoy类似的易用性。(管道并不是那么简单。有关如何查看此问题的信息。)

以下是文档中的一些示例。

运行一个过程:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(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')

原始答案:

我建议尝试Envoy。它是子流程的包装,后者旨在替换较旧的模块和功能。特使是人类的子过程。

自述文件中的示例用法:

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

管道周围的东西:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]


36

在Python中调用外部命令

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

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

为什么?

从Python 3.5开始,文档建议使用subprocess.run

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

这是最简单的用法示例-完全按照要求进行:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

run等待命令成功完成,然后返回一个CompletedProcess对象。相反,它可以引发TimeoutExpired(如果您给它提供一个timeout=参数)或CalledProcessError(如果失败并通过check=True)。

从上面的示例可以推断,默认情况下,stdout和stderr都通过管道传递到您自己的stdout和stderr。

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

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

捕获输出

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

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(我发现将版本信息放入stderr而不是stdout很有意思,并且有点违反直觉。)

传递命令清单

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

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

注意,仅args应按位置传递。

完整签名

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

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

popenargskwargs被给予Popen的构造。input可以是universal_newlines=True将通过管道传输到子进程的stdin 的字节字符串(或unicode,如果指定encoding或)。

该文档描述了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但是,直接使用pollwill 将使您能够访问其方法,包括,“ send_signal”,“ terminate”和“ wait”。

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

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

但更多的是信息Popen文档

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=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

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

剩下的内容Popen将作为读者的练习。


在此处可以找到主流程和子流程之间双向通讯的简单示例:stackoverflow.com/a/52841475/1349673
James Hirschorn,

第一个示例可能应该具有shell=True(或更好)将命令作为列表传递。
Tripleee

35

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

在此处获取更多信息。


2
虽然我同意总体建议,subprocess但并不能消除所有安全问题,并且存在一些令人讨厌的问题。
Tripleee '18

33

还有

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<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 up
u''                                             # Notepad window is closed by user, command returns

28

采用:

import os

cmd = 'ls -al'

os.system(cmd)

os-此模块提供了使用依赖于操作系统的功能的可移植方式。

对于更多的os功能,这里是文档。


2
也已弃用。使用子流程
Corey Goldberg

28

可能很简单:

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

1
这未能指出缺点,这些缺点在PEP-324中有更详细的说明。的文档os.system明确建议避免使用subprocess
Tripleee's

25

我非常喜欢shell_command的简单性。它建立在子流程模块的顶部。

这是文档中的示例:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

24

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

subprocess.Popen将<command>作为子进程执行。就我而言,我需要执行文件<a>,该文件需要与另一个程序<b>通信。

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

还有一个:(注意:kwrite的行为与其他应用程序不同。如果在Firefox上尝试以下操作,结果将有所不同。)

如果尝试这样做os.system("kwrite"),程序流将冻结,直到用户关闭kwrite。为了克服这个问题,我改为尝试os.system(konsole -e kwrite)。这个时间程序继续进行,但是kwrite成为了控制台的子进程。

任何人都运行kwrite而不是子进程(即,它必须在系统监视器中显示在树的最左侧)。


1
“任何人都在运行kwrite而不是子进程”是什么意思?
Peter Mortensen


22

subprocess.check_call如果您不想测试返回值,则非常方便。任何错误都会引发异常。


22

我倾向于将进程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)

17

无耻的插件,我为此写了一个库:P https://github.com/houqp/shell.py

目前,它基本上是popen和shlex的包装。它还支持管道命令,因此您可以在Python中更轻松地链接命令。因此,您可以执行以下操作:

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

16

在Windows中你可以导入subprocess模块,并通过调用运行外部命令subprocess.Popen()subprocess.Popen().communicate()subprocess.Popen().wait()如下:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : 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
    return 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

15

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

任务假脱机程序的示例:

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

有关任务后台处理程序(ts)的注意事项:

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

    ts -S <number-of-slots>

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


1
ts我所知道的任何发行版都不是标准的,尽管指向该指针的at用处很小。您可能还应该提及batch。与其他地方一样,该os.system()建议可能至少应提subprocess及其建议的替代方案。
Tripleee '18

15

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

from subprocess import Popen

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

签出subprocess.Popen


15

要从OpenStack Neutron获取网络ID :

#!/usr/bin/python
import os
netid = "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 net-list的输出

+--------------------------------------+------------+------+
| 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 |
+--------------------------------------+------------+------+

打印输出(networkId)

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

您不应该os.popen()在2016年推荐。Awk脚本可以轻松地用本机Python代码替换。
Tripleee '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.