在Python中调用外部命令

fre*_*Wer 4553 python shell terminal command subprocess

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

Dav*_*eau 4380

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

import subprocess
subprocess.run(["ls", "-l"])
Run Code Online (Sandbox Code Playgroud)

子进程系统的优势在于它更灵活(您可以获得stdout,stderr,"真实"状态代码,更好的错误处理等等).

官方文档建议在替代使用os.system模块():

模块提供了产卵新的流程和检索其结果更加强大的工具; 使用该模块比使用此函数[ subprocess] 更可取.

该" 与子模块更换旧的功能中"部分文档可能有一些有益的食谱.

  • @KevinWheeler你不应该使用`shell = True`,为此目的,Python附带[os.path.expandvars](https://docs.python.org/2/library/os.path.html#os.path. expandvars).在你的情况下你可以写:`os.path.expandvars("$ PATH")`.@SethMMorton请重新考虑您的评论 - > [为什么不使用shell = True](https://docs.python.org/2/library/subprocess.html#frequently-used-arguments) (26认同)
  • 至少在概念上简化:\n call("ls -l".split()) (12认同)
  • 您忘了说它至少需要python 3.5。例如,它不适用于python 3.4.3,这是Ubuntu 14.04 LTS的默认设置 (8认同)
  • 有没有办法使用变量替换?IE 我试图通过使用 `call(["echo", "$PATH"])` 来做 `echo $PATH`,但它只是回显了文字字符串 `$PATH` 而不是做任何替换。我知道我可以获得 PATH 环境变量,但我想知道是否有一种简单的方法可以让命令的行为与我在 bash 中执行的完全一样。 (5认同)
  • 如果要使用命令从参数中创建列表,**当shell = False时可以与subprocess一起使用的列表,然后使用shlex.split可以轻松实现此目的://docs.python.org/2/library/shlex.html#shlex.split (2认同)

Eli*_*ght 2880

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

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

    os.system("some_command < input_file | another_command > output_file")  
    
    Run Code Online (Sandbox Code Playgroud)

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

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

  3. 模块的Popensubprocess.这是为了取代它,os.popen但由于如此全面而具有稍微复杂的缺点.例如,你会说:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
    
    Run Code Online (Sandbox Code Playgroud)

    代替:

    print os.popen("echo Hello World").read()
    
    Run Code Online (Sandbox Code Playgroud)

    但是在一个统一的类而不是4个不同的popen函数中拥有所有选项是很好的.请参阅文档.

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

    return_code = subprocess.call("echo Hello World", shell=True)  
    
    Run Code Online (Sandbox Code Playgroud)

    请参阅文档.

  5. 如果您使用的是Python 3.5或更高版本,则可以使用新subprocess.run功能,它与上述功能非常相似,但更灵活,并CompletedProcess在命令完成执行时返回对象.

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

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

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

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
Run Code Online (Sandbox Code Playgroud)

并想象用户输入"我的妈妈不爱我&& rm -rf /".

  • 很好的答案/解释.这个答案如何证明Python本文所述的座右铭是正确的?http://www.fastcompany.com/3026446/the-fall-of-perl-the-webs-most-promising-language"在风格上,Perl和Python有不同的哲学.Perl最着名的格言是"有多种方式要做到这一点."Python的设计有一个明显的方法来实现它"看起来应该是另一种方式!在Perl中,我只知道两种执行命令的方法 - 使用back-tick或`open`. (16认同)
  • 如果使用Python 3.5+,请使用`subprocess.run()`.https://docs.python.org/3.5/library/subprocess.html#subprocess.run (8认同)
  • 这可以说是错误的方法.大多数人只需要`subprocess.run()`或其较旧的兄弟姐妹`subprocess.check_call()`等.对于这些不够的情况,请参阅`subprocess.Popen()`.`os.popen()`应该根本不应该被提及,或者甚至在"破解你自己的fork/exec/spawn代码之后". (5认同)
  • 通常需要知道的是子进程的STDOUT和STDERR做了什么,因为如果忽略它们,在某些(非常常见的)条件下,子进程最终会发出系统调用来写入STDOUT(STDERR也是?)这将超过操作系统为进程提供的输出缓冲区,并且操作系统将阻止它直到某个进程从该缓冲区读取.因此,使用当前推荐的方式,`subprocess.run(..)`,究竟是什么*"默认情况下这不会捕获stdout或stderr."*暗示?那么`subprocess.check_output(..)`和STDERR怎么样? (3认同)

Emm*_*Eff 326

我通常使用:

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()
Run Code Online (Sandbox Code Playgroud)

您可以随意使用stdout管道中的数据执行所需操作.事实上,你可以简单地省略那些参数(stdout=stderr=),它的行为就像os.system().

  • `.readlines()`一次读取*all*行,即它阻塞直到子进程退出(关闭它的管道末尾).要实时阅读(如果没有缓冲问题)你可以:`for line in iter(p.stdout.readline,''):print line,` (41认同)
  • 子进程可以在非交互模式下使用块缓冲而不是行缓冲,所以`p.stdout.readline()`(注意:结尾没有's`)在子进程填充之前不会看到任何数据缓冲.如果孩子没有产生太多数据,那么输出将不是实时的.在[问:为什么不使用管道(popen())中看到第二个原因?](http://www.noah.org/wiki/Pexpect#Q:_Why_not_just_use_a_pipe_.28popen.28.29.29.3F).提供了一些解决方法[在此答案中](http://stackoverflow.com/a/12471855/4279)(pexpect,pty,stdbuf) (13认同)
  • 您能否详细说明“如果没有缓冲问题”的意思?如果进程确实阻塞,则子进程调用也会阻塞。我的原始示例也可能发生同样的情况。关于缓冲还会发生什么? (4认同)
  • 缓冲问题仅在您想要实时输出时才有意义,并且在收到*all*数据之前不适用于不打印任何内容的代码 (4认同)
  • 这个答案暂时还不错,但是对于简单的任务,我们不再建议使用“ Popen”。这也不必要地指定了“ shell = True”。尝试使用subprocess.run()答案之一。 (2认同)

new*_*ver 207

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

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

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

import subprocess
import sys

# Some code here

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

# Some more code here
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid
Run Code Online (Sandbox Code Playgroud)

/*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)
Run Code Online (Sandbox Code Playgroud)

我没有检查其他平台上的代码,也不知道freebsd上行为的原因.如果有人知道,请分享您的想法.在Python中开始后台进程的Google搜索还没有任何亮点.

  • 以下是不正确的:"[o] n windows(win xp),父进程将不会完成,直到longtask.py完成其工作".父级将正常退出,但控制台窗口(conhost.exe实例)仅在最后一个附加进程退出时关闭,并且子级可能已继承父级控制台.在`creationflags`中设置`DETACHED_PROCESS`可以通过阻止子进程继承或创建控制台来避免这种情况.如果您想要一个新的控制台,请使用`CREATE_NEW_CONSOLE`(0x00000010). (5认同)
  • 有没有一种与操作系统无关的方式让进程在后台运行? (4认同)
  • 您可能还需要 CREATE_NEW_PROCESS_GROUP 标志。请参阅 [Popen 等待子进程即使直接子进程已终止](http://stackoverflow.com/q/13243807/4279) (3认同)
  • 我并不是说作为一个分离的进程执行是不正确的。也就是说,您可能需要为文件、管道或 `os.devnull` 设置标准句柄,因为否则某些控制台程序会以错误方式退出。当您希望子进程与父进程同时与用户交互时,创建一个新控制台。尝试在单个窗口中执行这两项操作会令人困惑。 (3认同)
  • 我看到`import subprocess as sp;sp.Popen('calc')` 没有等待子进程完成。似乎不需要创建标志。我错过了什么? (2认同)

sir*_*art 129

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

subprocess.call(['ping', 'localhost'])
Run Code Online (Sandbox Code Playgroud)

  • 这是不正确的:"**它会为你逃避shell,因此更加安全**".subprocess不执行shell转义,子进程不通过shell传递命令,因此不需要shell转义. (6认同)

Ale*_*nks 128

import os
cmd = 'ls -al'
os.system(cmd)
Run Code Online (Sandbox Code Playgroud)

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

  • popen [已弃用](https://docs.python.org/2/library/os.html#os.popen)支持[subprocess](https://docs.python.org/2/library/subprocess的.html). (10认同)

nim*_*ish 126

import os
os.system("your command")
Run Code Online (Sandbox Code Playgroud)

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

  • 不知道我近十年前的意思(检查日期!),但如果我不得不猜测,那将是没有完成验证. (5认同)
  • 这现在应该指向 `subprocess` 作为一个稍微更通用和便携的解决方案。运行外部命令当然本质上是不可移植的(您必须确保该命令在您需要支持的每个架构上都可用)并且将用户输入作为外部命令传递本质上是不安全的。 (2认同)
  • 请注意此人的时间戳:“正确”答案的票数是 40 倍,并且是答案 #1。 (2认同)

Tom*_*ler 80

有许多不同的库允许您使用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
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

plumbum是一个用于"类似脚本"的Python程序的库.您可以调用类似函数的程序sh.如果要运行没有shell的管道,Plumbum很有用.

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command
Run Code Online (Sandbox Code Playgroud)

Pexpect的

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')
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

使者

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

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

命令

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

该编辑基于JF Sebastian的评论.


小智 65

检查"pexpect"Python库.

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

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

child.expect('(?i)password')
Run Code Online (Sandbox Code Playgroud)


Jor*_*ona 65

我总是使用fabric这样的东西:

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

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

看一个例子:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
Run Code Online (Sandbox Code Playgroud)


Fac*_*sco 63

如果您需要从您所呼叫的命令的输出,那么你可以使用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'
Run Code Online (Sandbox Code Playgroud)

另请注意shell参数.

如果是shell True,则将通过shell执行指定的命令.如果您主要使用Python来提供它在大多数系统shell上提供的增强控制流,并且仍然希望方便地访问其他shell功能,例如shell管道,文件名通配符,环境变量扩展以及将〜扩展到用户家中,这将非常有用.目录.但是请注意,Python本身提供了很多贝壳般的功能实现(特别是glob,fnmatch,os.walk(),os.path.expandvars(),os.path.expanduser(),和shutil).

  • 请注意,`check_output` 需要一个列表而不是一个字符串。如果您不依赖带引号的空格来使您的调用有效,那么最简单、最易读的方法是`subprocess.check_output("ls -l /dev/null".split())`。 (2认同)

Hon*_*rek 62

使用标准库

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

import subprocess
subprocess.run(['ls', '-l'])
Run Code Online (Sandbox Code Playgroud)

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

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

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

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
Run Code Online (Sandbox Code Playgroud)

具有外部依赖性

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

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
Run Code Online (Sandbox Code Playgroud)

它是最好的subprocess包装纸.它是跨平台的,即它适用于Windows和类Unix系统.安装方式pip install plumbum.

另一种流行的库是SH:

from sh import ifconfig
print(ifconfig('wlan0'))
Run Code Online (Sandbox Code Playgroud)

但是,shWindows支持下降,所以它不像过去那样棒.安装方式pip install sh.


Usm*_*han 51

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

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()
Run Code Online (Sandbox Code Playgroud)

  • 将命令作为字符串传递通常是个坏主意 (3认同)
  • 我认为硬编码命令是可以接受的,如果它增加了可读性. (3认同)

Joe*_*Joe 48

更新:

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

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

运行一个过程:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
Run Code Online (Sandbox Code Playgroud)

提高失败的运行:

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

捕获输出:

>>> 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')
Run Code Online (Sandbox Code Playgroud)

原始答案:

我建议尝试特使.它是子进程的包装器,后者又旨在替换旧的模块和功能.特使是人类的子过程.

自述文件的用法示例:

>>> 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
''
Run Code Online (Sandbox Code Playgroud)

管道周围的东西:

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

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

>>> r.history
[<Response 'uptime'>]
Run Code Online (Sandbox Code Playgroud)


Zuc*_*nit 39

没有结果的输出:

import os
os.system("your command here")
Run Code Online (Sandbox Code Playgroud)

输出结果:

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
Run Code Online (Sandbox Code Playgroud)

  • “命令”在Python 3中不再可用。与“ os.system()”相比,您应该更喜欢“ subprocess” (2认同)

Ben*_*ein 35

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

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

import os
os.system('cat testfile')
Run Code Online (Sandbox Code Playgroud)


fam*_*man 33

2018 年 6 月 27 日发布Python 3.7.0 ( https://docs.python.org/3/whatsnew/3.7.html ) 开始,您可以以最强大而同样简单的方式实现您想要的结果。此答案旨在以简短的方式向您展示各种选项的基本摘要。如需深入解答,请参阅其他答案。


TL; DR 2021

最大的优点os.system(...)是它的简单性。subprocess更好并且仍然易于使用,尤其是从Python 3.5 开始

import subprocess
subprocess.run("ls -a", shell=True)
Run Code Online (Sandbox Code Playgroud)

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

像在壳里


首选方式

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

import subprocess
subprocess.run(["help"])
subprocess.run(["ls", "-a"])
Run Code Online (Sandbox Code Playgroud)

在列表中传递程序参数。对于包含空格的参数,不要包括\"-escaping。


高级用例

检查输出

以下代码不言自明:

import subprocess
result = 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?")
Run Code Online (Sandbox Code Playgroud)

result.stdout是所有正常的程序输出,不包括错误。阅读result.stderr以获取它们。

capture_output=True- 打开捕捉。否则result.stderrresult.stdoutNone。从Python 3.7可用。

text=True- 在Python 3.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")
Run Code Online (Sandbox Code Playgroud)

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

result.check_returncode()
Run Code Online (Sandbox Code Playgroud)

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

result = subprocess.run(..., check=True)
Run Code Online (Sandbox Code Playgroud)

stderr 应该在 stdout 里面

您可能希望在 stdout 中包含所有程序输出,甚至是错误。要完成此操作,请运行

result = subprocess.run(..., stderr=subprocess.STDOUT)
Run Code Online (Sandbox Code Playgroud)

result.stderr然后会Noneresult.stdout将包含一切。

将 shell=False 与参数字符串一起使用

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

import subprocess
import shlex
subprocess.run(shlex.split("ls -a"))
Run Code Online (Sandbox Code Playgroud)

就是这样。

常见问题

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

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

您正在运行一个没有shell=True. 使用列表 ( ["ls", "-a"]) 或设置shell=True

类型错误:[...] 无类型 [...]

检查您是否已设置capture_output=True.

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

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

subprocess.CalledProcessError: 命令 '[...]' 返回非零退出状态 1。

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

TypeError: init () 得到了一个意外的关键字参数 [...]

您可能使用的是早于 3.7.0 的 Python 版本;将其更新为可用的最新版本。否则,此 Stack Overflow 帖子中还有其他答案向您展示了较旧的替代解决方案。

  • 综上所述,“os.system(...)”确实可以有效使用。但是,一旦您编写的不仅仅是一个快速的 python 帮助程序脚本,我建议您使用不带 `shell=True` 的 subprocess.run 。有关 os.system 缺点的更多信息,我想建议您阅读这个答案:/sf/answers/3131175771/ (2认同)

stu*_*uck 32

还有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
Run Code Online (Sandbox Code Playgroud)


Aar*_*all 32

在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)
Run Code Online (Sandbox Code Playgroud)

为什么?

从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 Code Online (Sandbox Code Playgroud)

run等待命令成功完成,然后返回一个CompletedProcess对象.它可能会提高TimeoutExpired(如果你给它一个timeout=参数)或CalledProcessError(如果它失败并且你通过check=True).

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

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

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0
Run Code Online (Sandbox Code Playgroud)

捕获输出

如果要捕获输出,可以传递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''
Run Code Online (Sandbox Code Playgroud)

(我觉得有趣且有点违反直觉,版本信息被放到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'
Run Code Online (Sandbox Code Playgroud)

注意,只args应该通过位置传递.

完整签名

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

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

扩展签名

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

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

请注意,这表示只应按位置传递args列表.因此将剩余的参数作为关键字参数传递.

POPEN

什么时候使用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):
Run Code Online (Sandbox Code Playgroud)

但更多的是信息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)
Run Code Online (Sandbox Code Playgroud)

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

了解剩余的文档Popen将留给读者练习.


Mar*_*n W 31

os.system没关系,但有点过时了.它也不是很安全.相反,试试吧subprocess. subprocess不直接调用sh,因此比安全更安全os.system.

在这里获取更多信息.

  • 虽然我同意总体建议,但 `subprocess` 并没有消除所有的安全问题,并且有一些自己讨厌的问题。 (3认同)

Pri*_*ara 26

使用:

import os

cmd = 'ls -al'

os.system(cmd)
Run Code Online (Sandbox Code Playgroud)

os - 此模块提供了一种使用操作系统相关功能的便携方式.

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

  • 它也被弃用了.使用子进程 (2认同)

Sam*_*ine 26

它可以很简单:

import os
cmd = "your command"
os.system(cmd)
Run Code Online (Sandbox Code Playgroud)

  • 这没有指出缺点,在 [PEP-324](https://www.python.org/dev/peps/pep-0324/) 中有更详细的解释。`os.system` 的文档明确建议避免使用它以支持 `subprocess`。 (2认同)

abh*_*nan 22

使用os模块

import os
os.system("your command")
Run Code Online (Sandbox Code Playgroud)

例如

import os
os.system("ifconfig")
Run Code Online (Sandbox Code Playgroud)


小智 20

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

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

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

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

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

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


mdw*_*ott 20

我非常喜欢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
Run Code Online (Sandbox Code Playgroud)


cdu*_*001 19

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


Emi*_*röm 19

我倾向于将进程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)
Run Code Online (Sandbox Code Playgroud)


小智 18

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


hou*_*uqp 15

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

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

ex('echo hello shell.py') | "awk '{print $2}'"
Run Code Online (Sandbox Code Playgroud)


adm*_*ire 14

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

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()
Run Code Online (Sandbox Code Playgroud)

检查subprocess.Popen.


Swa*_*r C 14

在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)
Run Code Online (Sandbox Code Playgroud)

输出:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K
Run Code Online (Sandbox Code Playgroud)


Yuv*_*mon 14

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

任务假脱机程序的示例:

import os
os.system('ts <your-command>')
Run Code Online (Sandbox Code Playgroud)

有关任务假脱机程序(ts)的说明:

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

    ts -S <number-of-slots>

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


Val*_*sik 14

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
Run Code Online (Sandbox Code Playgroud)


N.N*_*vic 14

大多数情况:

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

import subprocess
import 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))
Run Code Online (Sandbox Code Playgroud)

它干净简单

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))
Run Code Online (Sandbox Code Playgroud)

正如The Zen of Python 中所述显式优于隐式

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

import subprocess
import shlex

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

Run Code Online (Sandbox Code Playgroud)


Gar*_*eld 12

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

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
Run Code Online (Sandbox Code Playgroud)

  • 这是否会在python 3.0中被弃用? (5认同)
  • 实际上,[Python 2.7中的[commands]文档](https://docs.python.org/2/library/commands.html)表示它已在2.6中弃用,并将在3.0中删除。 (2认同)

IRS*_*HAD 11

从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)
Run Code Online (Sandbox Code Playgroud)

星网表的输出

+--------------------------------------+------------+------+
| 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 |
+--------------------------------------+------------+------+
Run Code Online (Sandbox Code Playgroud)

打印输出(networkId)

27a74fcd-37c0-4789-9414-9531b7e3f126
Run Code Online (Sandbox Code Playgroud)


Uro*_*arc 10

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

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

pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")
Run Code Online (Sandbox Code Playgroud)

这是执行方法......

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]
Run Code Online (Sandbox Code Playgroud)


am5*_*am5 9

通常,我将以下函数用于外部命令,这对于长时间运行的进程尤其方便.下面的方法尾部过程输出 ,同时它正在运行并返回输出,引发一个例外,如果过程将失败.

如果在进程上使用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)
Run Code Online (Sandbox Code Playgroud)

你可以像这样调用它:

exec_long_running_proc(command = "hive", args=["-f", hql_path])
Run Code Online (Sandbox Code Playgroud)


Far*_*igo 9

对于subprocess在 Python 3.5+ 中使用,以下在 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'))
Run Code Online (Sandbox Code Playgroud)

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

上述代码的输出为:

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
Run Code Online (Sandbox Code Playgroud)


and*_*uso 8

使用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(" "))
Run Code Online (Sandbox Code Playgroud)


小智 8

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

import subprocess
subprocess.run('mkdir test.dir', shell=True)
Run Code Online (Sandbox Code Playgroud)

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

import subprocess
subprocess.call('mkdir test.dir', shell=True)
Run Code Online (Sandbox Code Playgroud)

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

import os
os.system('mkdir test.dir')
Run Code Online (Sandbox Code Playgroud)

最佳实践是使用subprocess而不是os,.run优于.call.您需要了解的有关子进程的所有信息.另请注意,所有Python文档都可从此处下载.我下载了打包为.zip的PDF文件.我之所以提到这一点是因为在tutorial.pdf(第81页)中对os模块进行了很好的概述.此外,它是Python编码人员的权威资源.

  • 根据https://docs.python.org/2/library/subprocess.html#frequently-used-arguments,“ shell = True”可能会引起安全问题。 (2认同)

Céd*_*ric 8

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

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

可以使用安装

pip install citizenshell
Run Code Online (Sandbox Code Playgroud)

然后使用如下:

from citizenshell import sh
assert sh("echo Hello World") == "Hello World"
Run Code Online (Sandbox Code Playgroud)

您可以将stdout与stderr分开,并提取退出代码,如下所示:

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

而且很酷的事情是,您不必在开始处理输出之前就等待底层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 + "!"
Run Code Online (Sandbox Code Playgroud)

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

>>> It is 14:24:52!
>>> It is 14:24:53!
>>> It is 14:24:54!
>>> It is 14:24:55!
Run Code Online (Sandbox Code Playgroud)

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


Sid*_*thy 8

可以使用两种主要方式使用Python执行Shell命令。以下两个示例均展示了如何pwd使用Python 获取当前工作目录()的名称。您可以使用任何其他Unix命令代替pwd

1.>第一种方法:可以使用Python中的os模块,然后使用system()函数在Python中执行shell命令。

import os
os.system('pwd')
Run Code Online (Sandbox Code Playgroud)

输出:

/Users/siddharth
Run Code Online (Sandbox Code Playgroud)

1.>第二种方法:另一种方法是使用子流程模块和call()函数。

import subprocess
subprocess.call('pwd')
Run Code Online (Sandbox Code Playgroud)

输出:

/Users/siddharth
Run Code Online (Sandbox Code Playgroud)


noɥ*_*ɐɹƆ 8

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

!ls
filelist = !ls
Run Code Online (Sandbox Code Playgroud)


Col*_*nic 7

2015年更新:Python 3.5添加了subprocess.run,它比subprocess.Popen更容易使用。我建议这样做。

>>> 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"], 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'')
Run Code Online (Sandbox Code Playgroud)

  • 已弃用不仅意味着“不再开发”,还意味着“不鼓励您使用它”。已弃用的功能可能随时中断、随时删除或可能存在危险。你永远不应该在重要的代码中使用它。弃用只是比立即删除功能更好的方法,因为它为程序员提供了时间来适应和替换其弃用的功能。 (10认同)
  • 对于危险,我并不是说它可以随时被删除(这是一个不同的问题),我也没有说使用这个特定的模块是危险的。然而,如果发现安全漏洞但不进一步开发或维护该模块,则可能会变得危险。(我不想说这个模块是否容易受到安全问题的影响,只是谈论一般已弃用的东西) (6认同)
  • 只是为了证明我的观点:“自版本 2.6 以来已弃用:命令模块已在 Python 3 中删除。请改用 subprocess 模块。” (4认同)

ima*_*hat 7

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

例如:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
Run Code Online (Sandbox Code Playgroud)


Jak*_*e W 7

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

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
Run Code Online (Sandbox Code Playgroud)

  • 当子进程退出而有一些数据被缓冲时,您的代码可能会丢失数据。改为阅读到 EOF,参见 [teed_call()](http://stackoverflow.com/q/4984428/4279) (4认同)

ras*_*hok 7

在Python中调用外部命令

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

ret = os.system('some_cmd.sh')
if ret != 0 :
    print 'some_cmd.sh execution returned failure'
Run Code Online (Sandbox Code Playgroud)

在后台调用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
Run Code Online (Sandbox Code Playgroud)

在后台调用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]
Run Code Online (Sandbox Code Playgroud)


Jen*_*man 6

在Python中运行外部命令有很多种不同的方法,所有这些方法都有自己的优缺点.

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

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

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

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


Dav*_*wii 6

使用:

import subprocess

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

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

['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',
 '']
Run Code Online (Sandbox Code Playgroud)


Raj*_*rma 6

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

Python Subprocess check_output很适合

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

import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
Run Code Online (Sandbox Code Playgroud)


dpo*_*man 6

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

例如,

!ls -ilF
Run Code Online (Sandbox Code Playgroud)


ame*_*hta 5

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

import os
os.system('ls')
Run Code Online (Sandbox Code Playgroud)

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

import subprocess
subprocess.check_call('ls')
Run Code Online (Sandbox Code Playgroud)

如果要将结果存储在变量中,请尝试:

import subprocess
r = subprocess.check_output('ls')
Run Code Online (Sandbox Code Playgroud)


Chi*_*nke 5

对于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)
Run Code Online (Sandbox Code Playgroud)

  • 在2015年增加了运行功能的答案.你重复了一遍.我认为这是投票减少的原因 (2认同)

gec*_*kos 5

如果您在命令中不使用用户输入,则可以使用以下命令:

\n
from os import getcwd\nfrom subprocess import check_output\nfrom shlex import quote\n\ndef sh(command):\n    return check_output(quote(command), shell=True, cwd=getcwd(), universal_newlines=True).strip()\n
Run Code Online (Sandbox Code Playgroud)\n

并将其用作

\n
branch = sh(\'git rev-parse --abbrev-ref HEAD\')\n
Run Code Online (Sandbox Code Playgroud)\n

shell=True将生成一个 shell,因此您可以使用管道和此类 shell 东西sh(\'ps aux | grep python\')。这对于运行硬编码命令和处理其输出非常方便。确保universal_lines=True输出以字符串而不是二进制形式返回。

\n

cwd=getcwd()将确保命令在与解释器相同的工作目录下运行。这对于 Git 命令来说很方便,就像上面的 Git 分支名称示例一样。

\n

一些食谱

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

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

\n
\n

安全考虑

\n

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

\n

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

\n
\n

即使使用shlex.quote(),在 shell 命令上使用用户输入时最好保持一点偏执。一种选择是使用硬编码命令来获取一些通用输出并按用户输入进行过滤。无论如何,使用shell=False将确保只有您想要执行的进程才会被执行,否则您会收到错误No such file or directory

\n

另外,对 也有一些性能影响shell=True,从我的测试来看,它似乎比shell=False(默认)慢 20% 左右。

\n
from os import getcwd\nfrom subprocess import check_output\nfrom shlex import quote\n\ndef sh(command):\n    return check_output(quote(command), shell=True, cwd=getcwd(), universal_newlines=True).strip()\n
Run Code Online (Sandbox Code Playgroud)\n


Vis*_*hal 5

import subprocess

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

在线试用


小智 5

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

\n

例子:

\n
import os\n\ntry:\n  os.system('ls')\n  pass\nexcept:\n  print("Error running command")\n  pass\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

是的,\xe2\x80\x99 就是这么简单!

\n


归档时间:

查看次数:

3251970 次

最近记录:

5 年,9 月 前