如何在Python脚本中调用外部命令(就像我在Unix shell或Windows命令提示符下键入它一样)?
如何在Python脚本中调用外部命令(就像我在Unix shell或Windows命令提示符下键入它一样)?
看着那(这 子进程模块 在标准库中:
from subprocess import call
call(["ls", "-l"])
的优点 子 与 系统 是它更灵活(你可以获得stdout,stderr,“真正的”状态代码,更好的错误处理等...)。
该 官方文件 推荐 子 替代os.system()上的模块:
该 子 模块提供了更强大的工具来产生新流程并检索其结果;使用该模块比使用此功能更可取[
os.system()
]。
“用子进程模块替换旧函数“节中的部分 子 文档可能有一些有用的食谱。
官方文件 子 模块:
看着那(这 子进程模块 在标准库中:
from subprocess import call
call(["ls", "-l"])
的优点 子 与 系统 是它更灵活(你可以获得stdout,stderr,“真正的”状态代码,更好的错误处理等...)。
该 官方文件 推荐 子 替代os.system()上的模块:
该 子 模块提供了更强大的工具来产生新流程并检索其结果;使用该模块比使用此功能更可取[
os.system()
]。
“用子进程模块替换旧函数“节中的部分 子 文档可能有一些有用的食谱。
官方文件 子 模块:
以下是调用外部程序的方法及其优缺点的摘要:
os.system("some_command with args")
将命令和参数传递给系统的shell。这很好,因为您实际上可以以这种方式一次运行多个命令并设置管道和输入/输出重定向。例如:
os.system("some_command < input_file | another_command > output_file")
但是,虽然这很方便,但您必须手动处理shell字符的转义,例如空格等。另一方面,这也允许您运行只是shell命令而不是外部程序的命令。看到 文件。
stream = os.popen("some_command with args")
会做同样的事情 os.system
除了它为您提供了一个类似文件的对象,您可以使用它来访问该进程的标准输入/输出。还有3种其他的popen变体,它们对i / o的处理方式略有不同。如果您将所有内容都作为字符串传递,那么您的命令将传递给shell;如果你将它们作为列表传递,那么你不必担心逃避任何事情。看到 文件。
该 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函数中拥有所有选项是很好的。看到 文件。
该 call
功能来自 subprocess
模块。这基本上就像是 Popen
class并获取所有相同的参数,但它只是等待命令完成并为您提供返回代码。例如:
return_code = subprocess.call("echo Hello World", shell=True)
看到 文件。
如果您使用的是Python 3.5或更高版本,则可以使用新的 subprocess.run
功能,这很像上面但更灵活,返回一个 CompletedProcess
命令完成执行时的对象。
os模块还具有C程序中的所有fork / exec / spawn函数,但我不建议直接使用它们。
该 subprocess
模块应该是你使用的。
最后请注意,对于所有将shell执行的最终命令作为字符串传递的方法,您负责转义它。 存在严重的安全隐患 如果您传递的字符串的任何部分无法完全信任。例如,如果用户正在输入字符串的某些/任何部分。如果您不确定,请仅将这些方法与常量一起使用。为了给您一些暗示,请考虑以下代码:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
并想象用户输入“我的妈妈不爱我&& 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()
。
有关将子进程与调用进程分离的一些提示(在后台启动子进程)。
假设您想从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 流程创建标志 到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中启动后台进程尚未解决任何问题。
我建议使用子进程模块而不是os.system,因为它会为你进行shell转义,因此更加安全: http://docs.python.org/library/subprocess.html
subprocess.call(['ping', 'localhost'])
import os
cmd = 'ls -al'
os.system(cmd)
如果要返回命令的结果,可以使用 os.popen
。但是,从版本2.6开始,这已经被弃用了 子进程模块,其他答案已经涵盖得很好。
import os
os.system("your command")
请注意,这是危险的,因为未清除该命令。我把它留给你去谷歌搜索关于'os'和'sys'模块的相关文档。有许多函数(exec *和spawn *)可以执行类似的操作。
我总是用 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)
检查“pexpect”Python库。
它允许交互式控制外部程序/命令,甚至ssh,ftp,telnet等。您只需键入以下内容:
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
有许多不同的库允许您使用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)。操作系统将始终运行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 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
包含for的包装函数 os.popen
,但它已从Python 3中删除 subprocess
是一个更好的选择。
该编辑基于J.F. Sebastian的评论。