问题描述:
如何在 Python 中调用外部命令,就好像我在 shell 或命令提示符中键入它一样?
解决方案1:
打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!
使用标准库中的 subprocess 模块:
import subprocess
subprocess.run(["ls", "-l"])
subprocess.run 相对于 os.system 的优势在于它更灵活(您可以获得 stdout、stderr、“real” status code、更好的 error handling 等…)。
甚至 the documentation for os.system 也建议使用 subprocess:
subprocess 模块提供了更强大的工具来生成新进程并检索它们的结果;使用该模块优于使用此功能。请参阅子流程文档中的用子流程模块替换旧功能部分以获取一些有用的秘诀。
在 Python 3.4 及更早版本上,使用 subprocess.call 而不是 .run:
subprocess.call(["ls", "-l"])
有没有办法使用变量替换? IE 我尝试使用 call(["echo", "$PATH"]) 来执行 echo $PATH,但它只是回显了文字字符串 $PATH 而不是进行任何替换。我知道我可以获得 PATH 环境变量,但我想知道是否有一种简单的方法可以让命令的行为与我在 bash 中执行它时完全一样。
@KevinWheeler 你必须使用 shell=True 才能工作。
@KevinWheeler 您不应该使用 shell=True,为此 Python 附带了 os.path.expandvars。在您的情况下,您可以写:os.path.expandvars("$PATH")。 @SethMMorton 请重新考虑您的评论-> Why not to use shell=True
如果我想通过管道传输 pip list | grep anatome 之类的东西怎么办?
许多参数版本如下所示:subprocess.run(["balcon.exe","-n","Tatyana","-t", "Hello world"])
解决方案2:
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。
调用外部程序的方法总结,包括它们的优缺点:
os.system 将命令和参数传递给系统的 shell。这很好,因为您实际上可以以这种方式一次运行多个命令并设置管道和输入/输出重定向。例如: os.system(“some_command < input_file | another_command > output_file”) 但是,虽然这很方便,但您必须手动处理空格等 shell 字符的转义。另一方面,这也允许您运行只是 shell 命令而不是实际外部程序的命令。 os.popen 将做与 os.system 相同的事情,只是它为您提供了一个类似文件的对象,您可以使用该对象来访问该进程的标准输入/输出。 popen 还有 3 个其他变体,它们对 i/o 的处理都略有不同。如果您将所有内容都作为字符串传递,那么您的命令将传递给 shell;如果您将它们作为列表传递,那么您无需担心转义任何内容。示例:print(os.popen(“ls -l”).read()) subprocess.Popen。这旨在作为 os.popen 的替代品,但缺点是由于过于全面而稍微复杂一些。例如,您会说: print subprocess.Popen(“echo Hello World”, shell=True, stdout=subprocess.PIPE).stdout.read() 而不是 print os.popen(“echo Hello World”).read () 但是很高兴将所有选项放在一个统一的类中,而不是 4 个不同的 popen 函数。请参阅文档。子进程调用。这基本上就像 Popen 类并接受所有相同的参数,但它只是等待命令完成并为您提供返回码。例如:return_code = subprocess.call(“echo Hello World”, shell=True) subprocess.run。仅限 Python 3.5+。与上述类似,但更加灵活,并在命令执行完成时返回 CompletedProcess 对象。 os.fork、os.exec、os.spawn 与它们的 C 语言对应物相似,但我不建议直接使用它们。
subprocess 模块应该是您使用的。
最后,请注意,对于将最终命令作为字符串传递给 shell 的所有方法,您有责任将其转义。如果您传递的字符串的任何部分都不能完全信任,则会产生严重的安全隐患。例如,如果用户正在输入字符串的某些/任何部分。如果您不确定,请仅将这些方法与常量一起使用。为了给您暗示含义,请考虑以下代码:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
并想象用户输入了可以擦除整个文件系统的“my mama didnt love me && rm -rf /”。
很好的答案/解释。这个答案如何证明本文所述的 Python 座右铭? fastcompany.com/3026446/…“从风格上讲,Perl 和 Python 有不同的理念。Perl 最著名的座右铭是“有不止一种方法可以做到”。Python 被设计成有一种明显的方法来做到这一点“看起来应该是另一种方法!在 Perl 中,我只知道执行命令的两种方法 - 使用反引号或 open。
如果使用 Python 3.5+,请使用 subprocess.run()。 docs.python.org/3.5/library/subprocess.html#subprocess.run
通常需要知道的是如何处理子进程的 STDOUT 和 STDERR,因为如果它们被忽略,在某些(非常常见的)条件下,最终子进程将发出系统调用来写入 STDOUT(STDERR 也是?)这将超过操作系统为进程提供的输出缓冲区,并且操作系统将导致它阻塞,直到某个进程从该缓冲区读取。那么,对于目前推荐的方式,subprocess.run(..),“This does not capture stdout or stderr by default.” 究竟意味着什么? subprocess.check_output(..) 和 STDERR 呢?
您推荐的哪些命令会阻止我的脚本?即,如果我想在 for 循环中运行多个命令,我该怎么做而不阻塞我的 python 脚本?我不关心命令的输出,我只想运行很多命令。
这可以说是错误的方法。大多数人只需要 subprocess.run() 或其年长的兄弟姐妹 subprocess.check_call() 等。对于这些还不够的情况,请参阅subprocess.Popen()。 os.popen() 可能根本不应该被提及,或者甚至在“破解你自己的 fork/exec/spawn 代码”之后出现。
解决方案3:
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。
典型实现:
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()。
.readlines() 一次读取所有 行,即阻塞直到子进程退出(关闭其管道末端)。要实时阅读(如果没有缓冲问题),您可以:for line in iter(p.stdout.readline, ''): print line,
您能否详细说明“如果没有缓冲问题”是什么意思?如果进程确实阻塞,则子进程调用也会阻塞。我原来的例子也可能发生同样的情况。在缓冲方面还会发生什么?
子进程可以在非交互模式下使用块缓冲而不是行缓冲,因此 p.stdout.readline()(注意:最后没有 s)在子进程填充其缓冲区之前不会看到任何数据。如果孩子没有产生太多数据,那么输出将不是实时的。请参阅 Q: Why not just use a pipe (popen())? 中的第二个原因。提供了一些解决方法 in this answer(pexpect、pty、stdbuf)
缓冲问题仅在您想要实时输出并且不适用于在收到所有数据之前不打印任何内容的代码时才重要
这个答案在当时还不错,但我们不应该再推荐 Popen 用于简单的任务。这也不必要地指定了 shell=True。尝试 subprocess.run() 答案之一。
解决方案4:
huntsbot.com – 高效赚钱,自由工作
关于将子进程与调用进程分离的一些提示(在后台启动子进程)。
假设您想从 CGI 脚本开始一个长任务。也就是说,子进程的寿命应该比 CGI 脚本执行进程长。
子流程模块文档中的经典示例是:
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 (Windows XP) 上,父进程在 longtask.py 完成其工作之前不会完成。这不是您在 CGI 脚本中想要的。该问题并非特定于 Python;在 PHP 社区中,问题是一样的。
解决方案是将 DETACHED_PROCESS Process Creation Flag 传递给 Windows API 中的底层 CreateProcess 函数。如果你碰巧安装了pywin32,你可以从win32process模块导入flag,否则你应该自己定义:
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 中启动后台进程还没有任何启示。
您可能还需要 CREATE_NEW_PROCESS_GROUP 标志。请参阅Popen waiting for child process even when the immediate child has terminated
我看到 import subprocess as sp;sp.Popen('calc') 没有等待子流程完成。似乎没有必要创建标志。我错过了什么?
@ubershmekel,我不确定您的意思,也没有安装 Windows。如果我没记错的话,如果没有标志,您将无法关闭启动 calc 的 cmd 实例。
以下是不正确的:“[o]n windows (win xp),父进程在 longtask.py 完成工作之前不会完成”。父进程会正常退出,但控制台窗口(conhost.exe 实例)仅在最后一个附加进程退出时才会关闭,并且子进程可能继承了父进程的控制台。在 creationflags 中设置 DETACHED_PROCESS 通过阻止子继承或创建控制台来避免这种情况。如果您想要一个新的控制台,请使用 CREATE_NEW_CONSOLE (0x00000010)。
我并不是说作为分离进程执行是不正确的。也就是说,您可能需要为文件、管道或 os.devnull 设置标准句柄,因为否则某些控制台程序会出现错误退出。当您希望子进程与父进程同时与用户交互时,请创建一个新控制台。尝试在一个窗口中同时执行这两项操作会令人困惑。
解决方案5:
保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com
import os
os.system("your command")
请注意,这是危险的,因为该命令没有被清除。我把它留给你去谷歌搜索’os’和’sys’模块的相关文档。有很多函数(exec* 和 spawn*)可以做类似的事情。
不知道我近十年前的意思(检查日期!),但如果我不得不猜测,那就是没有完成验证。
现在应该指出 subprocess 是一种更加通用和便携的解决方案。运行外部命令当然本质上是不可移植的(您必须确保该命令在您需要支持的每个架构上都可用)并且将用户输入作为外部命令传递本质上是不安全的。
解决方案6:
一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会
我建议使用 subprocess 模块而不是 os.system,因为它会为您进行 shell 转义,因此更安全。
subprocess.call(['ping', 'localhost'])
如果您想从带有参数的命令中创建一个列表,一个可以在 shell=False 时与 subprocess 一起使用的列表,然后使用 shlex.split 来轻松完成此操作{1 }(根据文档 docs.python.org/2/library/subprocess.html#popen-constructor,这是推荐的方式)
这是不正确的:“它会为你逃逸,因此更安全”。 subprocess 不会进行 shell 转义, subprocess 不会通过 shell 传递您的命令,因此无需 shell 转义。
解决方案7:
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。
import os
cmd = 'ls -al'
os.system(cmd)
如果要返回命令的结果,可以使用 os.popen。但是,自 2.6 版起已弃用此功能,转而支持 subprocess module,其他答案已经很好地涵盖了这一点。
huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式
弹出 is deprecated 以支持 subprocess。
您还可以使用 os.system 调用保存结果,因为它的工作方式与 UNIX shell 本身类似,例如 os.system('ls -l > test2.txt')
解决方案8:
huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求
有许多不同的库允许您使用 Python 调用外部命令。对于每个库,我都给出了描述并展示了调用外部命令的示例。我用作示例的命令是 ls -l(列出所有文件)。如果您想了解有关我列出的任何库的更多信息,并链接了每个库的文档。
来源
子进程:https://docs.python.org/3.5/library/subprocess.html
shlex:https://docs.python.org/3/library/shlex.html
操作系统:https://docs.python.org/3.5/library/os.html
sh:https://amoffat.github.io/sh/
铅:https://plumbum.readthedocs.io/en/latest/
pexpect:https://pexpect.readthedocs.io/en/stable/
面料:http://www.fabfile.org/
特使:https://github.com/kennethreitz/envoy
命令:https://docs.python.org/2/library/commands.html
这些都是图书馆
希望这将帮助您决定使用哪个库:)
子进程
子进程允许您调用外部命令并将它们连接到它们的输入/输出/错误管道(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.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 是在安全外壳 (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 是更好的选择。
解决方案9:
huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!
使用标准库
使用 subprocess module (Python 3):
import subprocess
subprocess.run(['ls', '-l'])
这是推荐的标准方式。然而,更复杂的任务(管道、输出、输入等)的构建和编写可能会很乏味。
关于 Python 版本的注意事项:如果您仍在使用 Python 2,subprocess.call 的工作方式类似。
专业提示:shlex.split 可以帮助您解析 run、call 和其他 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 安装。
解决方案10:
打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!
我总是使用 fabric 来处理这些事情,例如:
from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )
但这似乎是一个很好的工具:sh (Python subprocess interface)。
看一个例子:
from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
解决方案11:
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。
检查“pexpect”Python 库。
它允许对外部程序/命令,甚至 ssh、ftp、telnet 等进行交互式控制。您可以输入如下内容:
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
原文链接:https://www.huntsbot.com/qa/yO4A/how-do-i-execute-a-program-or-call-a-system-command?lang=zh_CN
HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com