*本站广告为第三方投放,如发生纠纷,请向本站索取第三方联系方式沟通
创想鸟 首页好文分享
python如何执行一个外部命令并获取输出_python执行外部命令并捕获输出的技巧
程序猿
•
2025年12月14日 12:05:43
•
好文分享 •
阅读 0
使用subprocess.run()是Python执行外部命令并捕获输出的推荐方法,它通过capture_output=True获取stdout和stderr,text=True返回字符串结果,check=True在命令失败时抛出异常;对于长时间运行的命令,应使用subprocess.Popen()实现非阻塞执行,配合communicate(timeout=…)避免程序卡死;安全方面需避免shell=True防止注入攻击,改用参数列表传递命令,并可通过env和cwd控制子进程环境与工作目录。
在Python里执行外部命令并捕获其输出,最直接也最推荐的方式是使用内置的
模块。它提供了非常灵活和强大的功能来创建新的进程、连接到它们的输入/输出/错误管道,并获取它们的返回码。简单来说,如果你需要运行一个shell命令或者其他可执行程序,并且想拿到它打印到屏幕上的内容,
就是你的首选。它封装了许多细节,让这个过程变得既安全又方便。
解决方案
要执行一个外部命令并获取其输出,最核心的
函数。这个函数在Python 3.5+版本中被引入,旨在替代许多老旧的
函数(比如
,
,
),提供了一个更统一、更现代的接口。
当你调用
时,你可以通过几个关键参数来控制其行为:
: 这是你想要执行的命令。通常,为了安全起见,我们建议将其作为一个列表传递,其中第一个元素是命令本身,后续元素是其参数。例如,
。如果你设置为
,也可以传递一个字符串,但那样会有安全隐患,我们稍后会提到。
: 这个参数告诉Python捕获外部命令的标准输出(stdout)和标准错误(stderr)。如果没有它,命令的输出会直接打印到你的控制台。
(或
): 当
时,默认捕获的输出是字节串(bytes)。如果你希望直接得到字符串,可以使用
(Python 3.7+)或者指定一个
,比如
。
: 如果外部命令以非零退出码结束(通常表示命令执行失败),这个参数会让
抛出一个
异常。这对于错误处理非常有用。
下面是一个基本示例:
会返回一个
对象,这个对象包含了命令执行的详细信息:
: 命令的退出码。0通常表示成功。
: 命令的标准输出(如果
)。
: 命令的标准错误(如果
)。
如何处理外部命令的错误输出和非零退出码? 处理外部命令的错误输出和非零退出码,是执行外部程序时一个不可避免,也是至关重要的环节。很多时候,我们不仅关心命令是否成功运行,更关心它失败的原因。
首先,
的
参数是处理非零退出码的利器。当外部命令以非零状态码退出时(比如一个
命令没有找到匹配项,或者一个编译命令遇到了语法错误),
会立即抛出一个
subprocess.CalledProcessError
异常。这使得你可以在Python代码中集中处理这些“失败”的情况,而不是让程序默默地继续执行,可能带着不正确的结果。
捕获这个异常后,你可以访问异常对象
的属性:
: 外部命令的退出码。
: 命令的标准输出(即使失败,也可能有部分输出)。
: 命令的标准错误输出。
这让你能够详细诊断问题。比如,一个编译命令失败了,你就可以把
打印出来,看到具体的
),
参数默认会将
和
都捕获到
对象的
和
属性中。如果你只想捕获
而不关心
,或者想对它们进行不同的处理,你可以使用
和
来更精细地控制。不过,对于大多数情况,
已经足够了,它会把它们分开存储。
有时候,非零退出码并不一定意味着“错误”。例如,
命令在没有找到匹配项时会返回1,这在脚本逻辑中可能是预期的行为,而不是需要抛异常的错误。在这种情况下,你可以选择不设置
,而是手动检查
:
import subprocesscommand = ['grep', 'nonexistent_pattern', 'nonexistent_file.txt'] # 肯定会失败的命令print("--- 不使用 check=True,手动检查退出码 ---")result = subprocess.run( command, capture_output=True, text=True, check=False # 不抛出异常)if result.returncode != 0: print(f"命令 '{' '.join(command)}' 执行失败,退出码: {result.returncode}") print(f"错误信息:n{result.stderr.strip()}") # 这里你可以根据 returncode 的值做更细致的判断 # 比如,如果是 grep 的 1,可能只是没找到,而不是真正的错误else: print(f"命令 '{' '.join(command)}' 执行成功。") print(f"输出:n{result.stdout.strip()}")# 考虑一个 grep 找到内容和没找到内容的场景print("n--- grep 示例 ---")with open("temp_file.txt", "w") as f: f.write("hello worldn") f.write("python is greatn")# 找到匹配项grep_command_found = ['grep', 'python', 'temp_file.txt']result_found = subprocess.run(grep_command_found, capture_output=True, text=True, check=False)print(f"grep 'python' (找到): returncode={result_found.returncode}, stdout='{result_found.stdout.strip()}'")# 未找到匹配项grep_command_not_found = ['grep', 'java', 'temp_file.txt']result_not_found = subprocess.run(grep_command_not_found, capture_output=True, text=True, check=False)print(f"grep 'java' (未找到): returncode={result_not_found.returncode}, stdout='{result_not_found.stdout.strip()}', stderr='{result_not_found.stderr.strip()}'")# 清理临时文件import osos.remove("temp_file.txt")
这种手动检查的方式给了你更大的控制权,但同时也意味着你需要自己处理所有可能的错误路径,不像
那样能够快速失败并抛出异常。选择哪种方式,取决于你的具体需求和对外部命令行为的理解。
在执行长时间运行的外部命令时,如何避免程序阻塞?
虽然好用,但它有一个特点:它是阻塞的。这意味着Python程序会暂停执行,直到外部命令完成并返回结果。对于那些需要瞬间完成的命令(比如
、
),这通常不是问题。但如果你的外部命令需要运行几秒、几分钟甚至更长时间(例如,一个大型编译任务、数据处理脚本或网络请求),你的Python程序会一直等待,直到命令结束,这会造成用户界面卡顿、服务器无响应等问题。
为了避免程序阻塞,你需要使用
。
是
模块的“底层”接口,它允许你启动一个子进程,然后立即返回,让你的Python程序可以继续执行其他任务。你可以把
想象成一个“启动器”,它只负责把命令扔出去,然后就不管了,让命令在后台自己跑。
使用
的基本流程是:
对象:这会启动子进程。
process = subprocess.Popen( ['long_running_script.sh'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True # 如果需要文本输出)
注意,这里我们通常会明确指定
和
,以便稍后能够捕获它们的输出。
方法。这个方法会阻塞,直到子进程结束,然后返回一个包含
和
的元组。
的
参数非常有用,它能防止程序无限期地等待一个卡住的子进程。如果超时,它会抛出
subprocess.TimeoutExpired
异常。
属性会告诉你子进程的退出码。在
之后,这个属性会被设置。
这里有一个例子,模拟一个耗时命令:
import subprocessimport timeimport os# 创建一个模拟长时间运行的脚本long_script_content = """#!/bin/bashecho "Starting long task..."sleep 5echo "Task finished."exit 0"""with open("long_task.sh", "w") as f: f.write(long_script_content)os.chmod("long_task.sh", 0o755) # 赋予执行权限print("--- 使用 Popen 启动长时间任务 ---")start_time = time.time()try: # 启动子进程,不阻塞主程序 process = subprocess.Popen( ['./long_task.sh'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) print(f"主程序:子进程已启动,PID: {process.pid}。我将继续做其他事情...") # 主程序可以在这里做一些其他工作 for i in range(3): print(f"主程序:正在执行其他任务... ({i+1}秒)") time.sleep(1) print("主程序:现在等待子进程完成并获取输出...") # 等待子进程完成并获取输出,设置超时为 10 秒 stdout, stderr = process.communicate(timeout=10) end_time = time.time() print(f"主程序:子进程已完成,耗时 {end_time - start_time:.2f} 秒。") print(f"子进程退出码: {process.returncode}") print(f"子进程标准输出:n{stdout.strip()}") if stderr: print(f"子进程标准错误:n{stderr.strip()}")except subprocess.TimeoutExpired: process.kill() # 超时时杀死子进程 stdout, stderr = process.communicate() # 再次communicate获取被杀死前的输出 print("主程序:子进程执行超时,已被终止。") print(f"部分输出:n{stdout.strip()}")except Exception as e: print(f"主程序:发生错误: {e}")finally: # 清理临时脚本 if os.path.exists("long_task.sh"): os.remove("long_task.sh")
如果你需要更高级的非阻塞操作,例如在子进程运行时实时读取其输出,或者同时管理多个子进程,你可能需要结合
模块或者
库来异步地读取管道,但这超出了基础
的范畴,属于更复杂的
配合
(带
)已经足够。
Python执行外部命令时,有哪些安全性和环境配置的考量?
执行外部命令不仅仅是运行起来那么简单,它还涉及到安全性和环境配置,这些往往是决定一个脚本健壮性和可靠性的关键因素。
安全性:
的陷阱
首先要提的是
这个参数。如果你在
或
中设置了
,那么你的命令会通过系统的shell来执行(在Linux上通常是
,在Windows上是
)。这听起来很方便,因为你可以直接传递一个字符串,里面包含管道符(
)、重定向符(
)等shell特性,比如
subprocess.run("ls -l | grep .py", shell=True)
。
然而,
是一个巨大的安全隐患,尤其当你的命令中包含任何来自用户或其他不可信源的数据时。这被称为“shell注入”攻击。如果用户输入被直接拼接到命令字符串中,恶意用户可以通过注入额外的shell命令来执行任意操作。
例如:假设你有一个命令是
,如果用户输入
是
,那么你的命令就变成了
,这会导致灾难性的后果。
最佳实践是:尽可能避免使用
。
相反,将命令和其参数作为列表传递给
函数。当
(这是默认值)时,Python会直接执行命令,而不是通过shell。这意味着它不会解析shell的特殊字符,从而避免了shell注入的风险。
# 安全的方式:使用列表传递参数subprocess.run(['ls', '-l', '/tmp'])# 不安全的方式:避免在用户输入中直接使用 shell=True# user_input = "malicious_file.txt; rm -rf /"# subprocess.run(f"cat {user_input}", shell=True) # 极度危险!
环境配置:
和
外部命令的执行环境对结果有很大影响。
模块提供了
和
参数,让你能够精确控制子进程的环境。
参数:允许你为子进程设置特定的
来确保命令能够被找到,或者设置特定的库路径。
参数接受一个字典,键值对就是环境变量 名和值。
import osmy_env = os.environ.copy() # 复制当前环境是好习惯my_env["MY_CUSTOM_VAR"] = "Hello From Python"my_env["PATH"] = "/usr/local/bin:" + my_env["PATH"] # 添加一个路径# 运行一个会打印环境变量的命令# 在 Linux/macOS 上:subprocess.run(['bash', '-c', 'echo $MY_CUSTOM_VAR && echo $PATH'], env=my_env, text=True)# 在 Windows 上:# subprocess.run(['cmd', '/c', 'echo %MY_CUSTOM_VAR% && echo %PATH%'], env=my_env, text=True)
参数:指定子进程的当前工作目录(Current Working Directory)。很多命令的行为都依赖于它们是在哪个目录下执行的。例如,
命令默认会列出当前目录的内容。如果你需要在一个特定的目录中运行命令,而不是Python脚本所在的目录,就可以使用
。
import os# 假设 /tmp/test_dir 存在且里面有文件if not os.path.exists("/tmp/test_dir"): os.makedirs("/tmp/test_dir") with open("/tmp/test_dir/file1.txt", "w") as f: f.write("test")print("--- 在不同工作目录执行 ls ---")# 在 Python 脚本当前目录执行 lsprint("当前目录的 ls:")subprocess.run(['ls'], text=True)# 在 /tmp/test_dir 目录下执行 lsprint("n/tmp/test_dir 目录的 ls:")subprocess.run(['ls'], cwd="/tmp/test_dir", text=True)# 清理os.remove("/tmp/test_dir/file1.txt")os.rmdir("/tmp/test_dir")
超时机制:
对于任何可能长时间运行的外部命令,设置一个超时机制是至关重要的。一个卡住的命令可能会导致你的Python程序永久阻塞,或者消耗大量系统资源。
提供了
参数,可以在指定时间后自动终止子进程。
import subprocessimport timeprint("--- 带有超时机制的命令 ---")try: # 尝试运行一个会持续 10 秒的命令,但只给它 3 秒时间 subprocess.run( ['sleep', '10'], timeout=3, check=True ) print("命令成功完成(这不应该发生)")except subprocess.TimeoutExpired: print("命令因超时被终止。这是预期的。")except subprocess.CalledProcessError as e: print(f"命令失败,退出码: {e.returncode}")except Exception as e: print(f"发生未知错误: {e}")
参数在
subprocess.Popen().communicate()
方法中也可用,用法类似。这大大提高了程序的鲁棒性,防止外部命令的意外行为影响到整个Python应用。
综合来看,理解并恰当使用
模块的这些参数,不仅能让你高效地执行外部命令,更能确保你的代码安全、稳定且易于维护。
以上就是python 如何执行一个外部命令并获取输出_py thon执行外部命令并捕获输出的技巧的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1372162.html
赞 (0)
打赏
微信扫一扫
支付宝扫一扫
相关推荐
如何跨越localhost使用本地图片? 问题: 在本地使用mask js库时,引入本地图片会报跨域错误。 解决方案: 要解决此问题,需要使用本地服务器启动文件,以http或https协议访问图片,而不是使用file://协议。例如: python -m http.server 8000 然后,可以…
css元素设置em和transition后,为何载入无放大效果 很多开发者在设置了em和transition后,却发现元素载入页面时无放大效果。本文将解答这一问题。 原问题:在视频演示中,将元素设置如下,载入页面会有放大效果。然而,在个人尝试中,并未出现该效果。这是由于macos和windows系统…
win10设置界面的鼠标移动显示周边的样式(探照灯效果)的实现方式 在windows设置界面的鼠标悬浮效果中,光标周围会显示一个放大区域。在前端开发中,可以通过多种方式实现类似的效果。 使用css 使用css的transform和box-shadow属性。通过将transform: scale(1.…
Win10设置界面中的鼠标移动探照灯效果实现指南 想要在前端开发中实现类似于Windows 10设置界面的鼠标移动探照灯效果,有两种解决方案:CSS 和 HTML/JS 组合。 CSS 实现 不幸的是,仅使用CSS无法完全实现该效果。 立即学习“前端免费学习笔记(深入)”; HTML/JS 实现 要…
如何在前端实现 Windows 10 设置界面中的鼠标移动探照灯效果 想要在前端开发中实现 Windows 10 设置界面中类似的鼠标移动探照灯效果,可以通过以下途径: CSS 解决方案 DEMO 1: Windows 10 网格悬停效果:https://codepen.io/tr4553r7/pe…
探索在前端中实现 Windows 10 设置界面鼠标移动时的探照灯效果 在前端开发中,鼠标悬停在元素上时需要呈现类似于 Windows 10 设置界面所展示的探照灯效果,这其中涉及到了元素外围显示光圈效果的技术实现。 CSS 实现 虽然 CSS 无法直接实现探照灯效果,但可以通过以下技巧营造出类似效…
跨域疑难:如何解决 mask 引入本地图片产生的跨域问题? 在使用 mask 导入本地图片时,你可能会遇到令人沮丧的跨域错误。为什么会出现跨域问题呢?让我们深入了解一下: mask 框架假设你以 http(s) 协议加载你的 html 文件,而当使用 file:// 协议打开本地文件时,就会产生跨域…
网页背景图在苹果浏览器上出现色差 一位用户在使用苹果浏览器访问网页时遇到一个问题,网页上方的背景图比底部的背景图明显更亮。 这个问题的原因很可能是背景图没有正确配置 background-size 属性。在 windows 浏览器中,背景图可能可以自动填满整个容器,但在苹果浏览器中可能需要显式设置 …
网页背景图像在苹果浏览器的色差问题 在不同浏览器中,网站的背景图像有时会出现色差。例如,在 Windows 浏览器中显示正常的上层背景图,在苹果浏览器中却比下层背景图更亮。 问题原因 出现此问题的原因可能是背景图像未正确设置 background-size 属性。 解决方案 为确保背景图像在不同浏览…
背景图在苹果电脑浏览器上亮度差异 问题描述: 在网页设计中,希望上部元素的背景图与页面底部的背景图完全对齐。而在 Windows 中使用浏览器时,该效果可以正常实现。然而,在苹果电脑的浏览器中却出现了明显的色差。 原因分析: 如果您已经排除屏幕分辨率差异的可能性,那么很可能是背景图的 backgro…
正则表达式助力文本输入验证 在文本输入框的验证中,经常遇到需要限定输入内容的情况。例如,输入框只能输入整数,第一位可以为负号。对于不会使用正则表达式的人来说,这可能是个难题。下面我们将提供三种正则表达式,分别满足不同的验证要求。 1. 可选负号,任意数量数字 如果输入框中允许第一位为负号,后面可输入…
解决 VS Code 折叠代码复制问题 在 VS Code 中使用折叠功能可以帮助组织长代码,但使用复制功能时,可能会遇到只复制可见部分的问题。以下是如何解决此问题: 当代码被折叠时,可以使用以下简单操作复制整个折叠代码: 按下 Ctrl + C (Windows/Linux) 或 Cmd + C …
在全栈和平均栈开发方面工作了 6 年多,我可以告诉您,虽然这两种方法都是流行且有效的方法,但它们满足不同的需求,并且有自己的优点和缺点。这两个堆栈都可以帮助您创建 Web 应用程序,但它们的实现方式却截然不同。如果您在两者之间难以选择,我希望我在两者之间的经验能给您一些有用的见解。 在这篇文章中,我…
依赖关系 Shopify CLI:一种命令行界面工具,可帮助您开发和管理 Shopify 主题。TailwindCSS:实用程序优先的 CSS 框架,用于快速构建自定义设计。 设置 我们使用 Tailwind 作为独立的 CLI 工具。更多信息可以参考官方指南。 注意:如果您在配备 Intel 处理…
本教程演示如何在新项目中从头开始配置 django 和 tailwindcss。 django 设置 创建一个名为 .venv 的新虚拟环境。 # windows$ python -m venv .venv$ .venvscriptsactivate.ps1(.venv) $# macos/linu…
在我看来,这篇文章是我昨天写的。 好的。所以…我可能已经完全重建了我的网站…再次 sid ・21 年 12 月 23 日 #webdev #showdev #html #css 然而,近四年过去了,事后看来,我可以自信地说,我早期在网页设计方面的尝试是,好吧,我们只能说不太出…
→ Python → JavaScript → Java → C# → 红宝石 → 斯威夫特 → 科特林 → C++ → PHP → 出发 → R → 打字稿 []https://x.com/e_opore/status/1811567830594388315?t=_j4nncuiy2wfbm7ic…
css设置超出显示省略号的方法:1、使用“overflow:hidden;”语句把超出的部分隐藏起来;2、使用“text-overflow:ellipsis;”语句在文本溢出包含元素时,显示省略符号来代表被隐藏的部分。 本教程操作环境:windows7系统、CSS3&&HTML5版、…
本篇文章给大家带来的内容是关于如何使用纯css实现windows启动界面的动画效果 ,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 效果预览 源代码下载 https://github.com/comehope/front-end-daily-challenges 代码解读 定义 d…
可在Jimdo实现HTML5弹窗的四种方法:一、用内置“弹窗链接”模块;二、通过HTML区块注入精简dialog结构(需配合内联CSS);三、外部托管HTML+iframe嵌入;四、纯CSS :target伪类无JS方案。 如果您希望在Jimdo网站中实现HTML5弹窗效果,但发现平台默认不支持直接…