it-swarm.cn

在Python中调用外部命令

如何从Python脚本中调用外部命令(就像我在Unix Shell或Windows命令提示符下键入它一样)?

4038
freshWoWer

查看标准库中的 subprocess模块​​

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

subprocesssystem的优点是它更灵活(你可以获得stdout,stderr,“真实”状态代码,更好的错误处理等等)。

官方文档 推荐subprocess模块替代os.system():

subprocess模块提供了更强大的工具来生成新进程并检索其结果;使用该模块比使用此函数[ os.system() ]更可取。

subprocess文档中的“ 用子进程模块替换旧函数 ”部分可能有一些有用的配方。

3905
David Cournapeau

以下是调用外部程序的方法及其优缺点的摘要:

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

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

    但是,虽然这很方便,但您必须手动处理Shell字符的转义,例如空格等。另一方面,这也允许您运行只是Shell命令而不是实际外部程序的命令。请参阅 文档

  2. stream = os.popen("some_command with args")将执行与os.system相同的操作,除了它为您提供了一个类似文件的对象,您可以使用它来访问该进程的标准输入/输出。还有3种其他的popen变体,它们对i/o的处理方式略有不同。如果将所有内容都作为字符串传递,那么您的命令将传递给Shell;如果你将它们作为列表传递,那么你不必担心逃避任何事情。请参阅 文档

  3. Popen模块的subprocess类。这是为了取代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. call模块中的subprocess函数。这基本上就像Popen类一样,并且接受所有相同的参数,但它只是等待命令完成并为您提供返回代码。例如:

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

    请参阅 文档

  5. 如果您使用的是Python 3.5或更高版本,则可以使用新的 subprocess.run 函数,它与上面的内容很相似,但更灵活,并在命令完成执行时返回 CompletedProcess object。

  6. Os模块还具有C程序中的所有fork/exec/spawn函数,但我不建议直接使用它们。

subprocess模块可能应该是你使用的。

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

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

并想象用户输入“我的妈妈不爱我&& rm -rf /”。

2665
Eli Courtwright

我通常使用:

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

292
EmmEff

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

假设您想从CGI脚本启动一个长任务,即子进程应该比CGI脚本执行过程更长寿。

子流程模块docs的经典示例是:

import subprocess
import sys

# some code here

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

# some more code here

这里的想法是你不想在“调用子进程”行中等待,直到longtask.py完成。但目前尚不清楚在这个例子中“更多代码”这一行之后会发生什么。

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

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

解决方案是将DETACHED_PROCESS Process Creation Flag 传递给win 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中开始后台进程的Google搜索还没有任何亮点。

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

如果要返回命令的结果,可以使用 os.popen 。但是,从版本2.6开始,这已被弃用,而不是 subprocess模块​​ ,其他答案已经很好地解决了。

113
Alexandra Franks

我建议使用子进程模块而不是os.system,因为它会为你进行Shell转义,因此更加安全: http://docs.python.org/library/subprocess.html

subprocess.call(['ping', 'localhost'])
113
sirwart
import os
os.system("your command")

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

101
nimish

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

来源:

这些都是库:

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

subprocess

子进程允许您调用外部命令并将它们连接到它们的输入/输出/错误管道(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用于“依赖于操作系统的功能”。它还可以用于使用os.systemos.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中那样调用类似函数的程序。如果要在没有Shell的情况下运行管道,Plumbum很有用。

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

pexpect

pexpect允许您生成子应用程序,控制它们并在其输出中查找模式。对于期望在Unix上使用tty的命令,这是替代子进程的更好的替代方法。

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

fabric

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

envoy

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

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

命令

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

该编辑基于J.F. Sebastian的评论。

63
Tom Fuller

我总是使用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)
60
Jorge E. Cardona

检查“pexpect”Python库。

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

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

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

如果你需要你正在调用的命令的输出,[。_____。]那么你可以使用 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,则将通过命令行管理程序执行指定的命令。如果您主要使用Python来提供它在大多数系统shell上提供的增强控制流,并且仍然希望方便地访问其他Shell功能,例如Shell管道,文件名通配符,环境变量扩展以及扩展到用户家中,这将非常有用。目录。但请注意,Python本身提供了许多类似Shell的功能的实现(特别是globfnmatchos.walk()os.path.expandvars()os.path.expanduser()shutil)。

53
Facundo Casco

使用标准库

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

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

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

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

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

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安装。

51
Honza Javorek

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

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()
45
Usman Khan

更新:

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

以下是 docs 的一些示例。

运行一个过程:

>>> 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 。它是子进程的包装器,反过来 旨在替换 较旧的模块和函数。特使是人类的子过程。

来自 readme 的示例用法:

>>> 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'>]
42
Joe

没有结果的输出:

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

输出结果:

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
34
Zuckonit

https://docs.python.org/2/library/subprocess.html

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

import os
os.system('cat testfile')
28
Ben Hoffstein

还有 Plumbum

>>> 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
27
stuckintheshuck

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

获取更多信息 这里

27
Martin W

在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可以是一串字节(或unicode,如果指定编码或universal_newlines=True),它将被传送到子进程的stdin。

文档描述timeout=check=True比我更好:

Timeout参数传递给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','terminate'和'wait'。

这是 source 中给出的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上的剩余文档将留给读者练习。

24
Aaron Hall

它可以很简单:

import os
cmd = "your command"
os.system(cmd)
23
Samadi Salahedine

使用:

import os

cmd = 'ls -al'

os.system(cmd)

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

对于更多os函数, here 是文档。

23
Priyankara

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

19
cdunn2001

我倾向于使用 subprocessshlex (以处理引用字符串的转义):

>>> 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)
18
Emil Stenström

os.system不允许您存储结果,因此如果您想将结果存储在某个列表中,或subprocess.call可以工作。

17
Saurabh Bangad

这里有另一个不同之处,前面没有提到过。

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

我尝试了subprocess,执行成功了。但是<b>无法与<a>进行通信。[。_____。]当我从终端运行时,一切正常。

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

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

任何人都运行kwrite不是一个子进程(即在系统监视器中它必须出现在树的最左边的边缘)。

17
Atinc Delican

我很喜欢 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
16
mdwhatcott

使用os模块

import os
os.system("your command")

例如

import os
os.system("ifconfig")
15
abhi krishnan

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

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

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

在Linux下,如果你想调用一个独立执行的外部命令(将在python脚本终止后继续运行),你可以使用一个简单的队列作为 task spoolerat command

任务假脱机程序的示例:

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

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

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

    ts -S <number-of-slots>

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

14
Yuval Atzmon

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

from subprocess import Popen

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

检查 subprocess.Popen

13
admire

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

# 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
12
Swadhikar C

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

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
11
Garfield

从openstack中子获取网络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网表

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

这是我的两分钱:在我看来,这是处理外部命令时的最佳做法......

这些是execute方法的返回值......

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]
10
Uroš Jarc

Invoke是一个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
8
Valery Ramusik

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

Python Subprocess check_output很适合

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

import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
7
Rajiv Sharma

使用:

import subprocess

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

它提供了Nice输出,更易于使用:

['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',
 '']
7
David Okwii

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

例如:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
7
imagineerThat

在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。我们可以在后台启动命令并等待它完成。之后我们可以得到stdout和stderr。

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 it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]
6
rashok

在Python中运行外部命令有很多不同的方法,[。_____。]并且所有这些方法都有自己的优缺点。

我的同事和我一直在编写Python系统管理工具,因此我们需要运行大量外部命令,有时您希望它们以异步方式阻塞或运行,超时,每秒更新等。

还有不同的处理返回代码和错误的方法,[。_____。]你可能想要解析输出,并提供新的输入(以 期望 种类型)。或者您需要重定向stdin,stdout和stderr以在不同的tty中运行(例如,在使用屏幕时)。

所以你可能不得不围绕外部命令编写很多包装器。所以这里有一个我们编写的Python模块,它可以处理几乎你想要的任何东西,如果没有,它非常灵活,所以你可以轻松扩展它:

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

6
Jens Timmerman

作为一个例子(在Linux中):

import subprocess
subprocess.run('mkdir test.dir', Shell=True)

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

import subprocess
subprocess.call('mkdir test.dir', Shell=True)

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

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

最佳实践是使用subprocess而不是os,.run优于.call。 你需要知道的有关子进程的所有内容是 这里 。[。_____。]另外,请注意所有Python文档都可以从 这里 下载。我下载了_​​PDF打包为.Zip。我之所以提到这一点是因为在tutorial.pdf(第81页)中对os模块有一个很好的概述。此外,它是Python编码人员的权威资源。

6
user8468899

对于Python 3.5+,建议您使用子进程模块中的 run函数 。这将返回一个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)
5
Chiel ten Brinke

通常,我将以下函数用于外部命令,这对于 长时间运行的进程特别有用 。下面的方法 tails进程输出 while 它正在运行并返回输出, 引发异常 如果进程失败。

如果使用进程上的 poll()方法完成进程

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 finished
    while True:
        nextline = process.stdout.readline().decode('UTF-8')
        if nextline == '' and process.poll() is not None:
            break
        sys.stdout.write(nextline)
        sys.stdout.flush()

    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise Exception(command, exitCode, output)

您可以像这样调用它:

exec_long_running_proc(command = "Hive", args=["-f", hql_path])
5
am5

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

import os
os.system('ls')

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

import subprocess
subprocess.check_call('ls')

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

import subprocess
r = subprocess.check_output('ls')
4
amehta

使用 subprocess.call

from subprocess import call

# using list
call(["echo", "Hello", "world"])

# single string argument varies across platforms so better split it
call("echo Hello world".split(" "))
4
andruso

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

import subprocess

..
process = subprocess.Popen(..)   # Pass command and arguments to the function
stdout, stderr = process.communicate()   # Get command output and error
..
4
Asif Hasnain

调用命令的方法有很多种。

  • 例如:

如果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)
4
liuyip

如果需要从Python笔记本(例如 Jupyter ,Zeppelin,Databricks或Google Cloud Datalab)调用Shell命令,则可以使用!前缀。

例如,

!ls -ilF
3
dportman

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

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

它可以使用安装 

pip install citizenshell

然后使用如下:

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

您可以从stderr中分离stdout并提取退出代码,如下所示:

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

由于wait = 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找到

3
Cédric

有两种主要方法可以使用Python执行Shell命令。下面提到的示例都显示了如何使用Python获取当前工作目录(pwd)的名称。您可以使用任何其他Unix命令代替pwd。 

1.>第一种方法: 可以使用python中的 os 模块和 system() function来从中执行Python命令。

import os
os.system('pwd')

输出:

/Users/siddharth

1.>第二种方法: 另一种方法是使用 subprocess module和 call() function。 

import subprocess
subprocess.call('pwd')

输出:

/Users/siddharth
3
Siddharth Satpathy

我建议使用以下方法'run',它将帮助我们将STDOUT,STDERR和退出状态作为字典;这个调用者可以通过'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
2
Viswesn

经过一些研究,我有以下代码,对我来说效果很好。它基本上实时打印stdout和stderr。希望它可以帮助其他需要它的人。

stdout_result = 1
stderr_result = 1


def stdout_thread(pipe):
    global stdout_result
    while 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_result
    while 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 ' + cwd
    else:
        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
2
Jake W

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

import shlex
import psutil
import 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)
1
Asav Patel

Eli上面描述的 subprocess模块​​ 非常强大,但是进行bog标准系统调用并检查其输出的语法是不必要的。

进行系统调用的最简单方法是使用 命令模块 (仅限Linux)。

> import commands
> commands.getstatusoutput("grep matter alice-in-wonderland.txt")
(0, "'Then it doesn't matter which way you go,' said the Cat.")

元组中的第一项是进程的返回码。第二项是其标准输出(和标准错误,合并)。


Python开发人员已经“弃用”了命令模块,但这并不意味着你不应该使用它。只是他们不再开发它了,这是可以的,因为它已经完美(在它的小而重要的功能)。

1
Colonel Panic

由于一些答案与以前版本的python相关或者正在使用os.system模块,因此我会向像我这样打算在python 3.5+中使用subprocess的人发布这个答案。以下是我在Linux上的诀窍:

import subprocess

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

documentation 中所述,PIPE值是字节序列,为了正确显示它们,应该考虑解码。对于python的更高版本,text=Trueencoding='utf-8'被添加到 subprocess.run() 的kwargs。 

上述代码的输出是:

total 113M
-rwxr-xr-x  1 farzad farzad  307 Jan 15  2018 vpnscript
-rwxrwxr-x  1 farzad farzad  204 Jan 15  2018 ex
drwxrwxr-x  4 farzad farzad 4.0K Jan 22  2018 scripts
.... # some other lines
1
Farzad Vertigo

如果你是 _不_ 在命令中使用用户输入,你可以使用它

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 branch name示例一样。

一些食谱

  • 以兆字节为单位的可用内存:sh('free -m').split('\n')[1].split()[1]
  • 可用空间/百分比sh('df -m /').split('\n')[1].split()[4][0:-1]
  • cpu load sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])

但是从文档来看,这对用户输入来说并不安全:

安全注意事项¶

与其他一些popen函数不同,此实现永远不会隐式调用系统Shell。这意味着所有字符(包括Shell元字符)都可以安全地传递给子进程。如果通过Shell = True显式调用Shell,则应用程序有责任确保适当地引用所有空格和元字符以避免Shell注入漏洞。

使用Shell = True时,shlex.quote()函数可用于正确转义将用于构造Shell命令的字符串中的空格和Shell元字符。

在Shell命令上使用用户输入时,即使使用shlex.quote()也可以保持一点偏执。一种选择是使用硬编码命令来获取一些通用输出并通过用户输入进行过滤。无论如何使用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
0
geckos