✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:python综合应用,基础语法到高阶实战教学
景天的主页:景天科技苑
文章目录
- 在Python代码中执行Linux命令的详细用法教程
- 一、使用`os`模块执行Linux命令
- 1.1 `os.system()`
- 1.2 `os.popen()`
- 二、使用`subprocess`模块执行Linux命令
- 2.1 `subprocess.run()`
- 2.2 `subprocess.Popen()`
- 2.3 `subprocess.call()`
- 三、使用`sh`模块执行Linux命令
- 四、安全注意事项
- 五、进阶用法与技巧
- 5.1 异步执行命令
- 5.2 捕获命令的实时输出
- 5.3 使用环境变量
- 六、总结
在Python代码中执行Linux命令的详细用法教程
在Python开发过程中,经常需要执行Linux系统命令来完成各种任务,如文件操作、系统状态检查等。Python提供了多种方式来调用和执行系统命令,其中os
模块和subprocess
模块是最常用的两种。本文将详细介绍如何在Python代码中执行Linux命令,并结合实际案例来演示这些方法的使用。
一、使用os
模块执行Linux命令
1.1 os.system()
os.system()
函数是os
模块中最直接执行系统命令的方式。它会执行指定的命令并等待命令执行完成,然后返回命令的退出状态码。退出状态码为0通常表示命令执行成功,非0值表示执行失败。
示例代码:
import os# 执行ls命令并打印结果
result = os.system('ls -l')
print(f"命令执行结果: {result}")# 如果需要获取命令的输出,则此方法不适用,因为os.system()不直接返回命令的输出。
1.2 os.popen()
os.popen()
函数可以执行命令并返回一个文件对象,你可以像操作文件一样读取命令的输出。这种方式比os.system()
更灵活,因为它允许你获取命令的输出。
示例代码:
import os# 使用os.popen执行命令并读取输出
with os.popen('ls -l') as command:for line in command:print(line, end='')# 注意:os.popen()在Python 3.x中已被标记为不推荐使用,推荐使用subprocess模块。
二、使用subprocess
模块执行Linux命令
subprocess
模块提供了更强大和灵活的执行系统命令的功能。它允许你创建新的进程,连接到它们的输入/输出/错误管道,并获取它们的返回码。
2.1 subprocess.run()
subprocess.run()
是Python 3.5及以上版本中推荐使用的函数,用于执行命令并等待其完成。它返回一个CompletedProcess
实例,其中包含命令的输出、错误输出和返回码。
示例代码:
import subprocess# 执行ls命令并捕获输出
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)# 检查命令是否成功执行
if result.returncode == 0:print(f"命令输出:\n{result.stdout}")
else:print(f"命令执行失败,错误输出:\n{result.stderr}")
2.2 subprocess.Popen()
subprocess.Popen()
用于创建新的进程,并且不等待命令执行完成。它返回一个Popen
对象,允许你与子进程进行交互。这种方式提供了更细粒度的控制,比如可以实时获取命令的输出。
示例代码:
import subprocess# 使用Popen执行命令并实时获取输出
process = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, text=True)# 读取输出
for line in process.stdout:print(line, end='')# 等待子进程完成
process.wait()# 检查命令是否成功执行
if process.returncode == 0:print("命令执行成功")
else:print("命令执行失败")
2.3 subprocess.call()
subprocess.call()
执行指定的命令,并等待命令执行完成。它返回命令的退出状态码,但不提供直接获取命令输出的方式。
示例代码:
import subprocess# 执行命令并获取退出状态码
result = subprocess.call(['ls', '-l'])# 检查命令是否成功执行
if result == 0:print("命令执行成功")
else:print("命令执行失败")# 注意:如果需要获取命令的输出,请使用subprocess.run()或subprocess.Popen()。
三、使用sh
模块执行Linux命令
sh
是一个第三方库,提供了一个更简洁和友好的方式来执行系统命令。它模仿了Shell的语法和行为,使得在Python中执行Shell命令变得更加容易。
安装sh模块:
首先,你需要安装sh
模块。可以通过pip来安装:
pip install sh
示例代码:
import sh# 创建一个ls命令对象
ls = sh.Command("ls")# 执行命令,并将结果输出到终端
ls("-l")# 或者,你可以捕获命令的输出
output = ls("-l", _out=sh.piping.PIPE)
print(output.stdout.decode('utf-8')) # 注意解码输出,因为sh库默认返回bytes# 使用sh库执行带参数的命令也很直观
grep = sh.Command("grep")
result = grep("some_text", "some_file.txt")if result.exit_code == 0:print("找到匹配项:", result.stdout.decode('utf-8'))
else:print("未找到匹配项")# sh库还提供了管道和重定向的支持
cat = sh.Command("cat")
sort = sh.Command("sort")# 管道示例:将cat的输出传递给sort
sorted_output = (cat("input.txt") | sort)()
print(sorted_output.stdout.decode('utf-8'))# 注意:在上面的管道示例中,我们使用了Python的管道操作符 `|`,但在 `sh` 库中是通过特殊方式实现的。
# 实际使用时,需要在括号内调用整个管道表达式,如上例所示。
四、安全注意事项
在Python中执行系统命令时,需要特别注意安全问题,特别是当命令或命令的参数来自不可信的源时。以下是一些安全建议:
-
避免命令注入:如果命令的某部分(如参数)来自用户输入,请确保不要直接将其插入到命令字符串中。使用列表形式(如
subprocess.run(['ls', '-l'])
)而不是字符串形式(如subprocess.run('ls -l')
),因为列表形式能够更好地处理包含空格、引号等特殊字符的参数。 -
限制权限:确保执行命令的进程没有不必要的权限。例如,如果命令不需要写入文件系统的权限,则不要以root用户身份运行Python脚本。
-
验证输入:在将输入用于命令之前,验证其是否符合预期格式和范围。
-
使用安全的库:对于复杂的需求,考虑使用专门为此设计的库,这些库可能已经解决了安全问题和边缘情况。
-
记录和监控:对执行的命令和结果进行记录和监控,以便在出现问题时能够进行回溯和调查。
五、进阶用法与技巧
5.1 异步执行命令
如果你需要在不阻塞主程序的情况下执行系统命令,可以考虑使用异步编程。Python的asyncio
库可以与subprocess
模块结合使用,通过asyncio.create_subprocess_exec()
或asyncio.create_subprocess_shell()
函数来异步执行命令。
示例代码(使用asyncio.create_subprocess_exec()
):
import asyncioasync def run_command(cmd, *args):# 创建子进程process = await asyncio.create_subprocess_exec(cmd, *args,stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.PIPE,)# 等待子进程完成stdout, stderr = await process.communicate()# 解码输出if stdout:print(f'[stdout]\n{stdout.decode()}')if stderr:print(f'[stderr]\n{stderr.decode()}')# 异步执行ls命令
asyncio.run(run_command('ls', '-l'))
注意:在这个例子中,我们使用了asyncio.run()
来运行异步函数,这是Python 3.7及以上版本中推荐的方式。
5.2 捕获命令的实时输出
如果你想要实时捕获命令的输出,而不是等待命令执行完成后再一次性获取输出,你可以使用subprocess.Popen()
结合多线程或多进程来实现。但更简洁的方法是使用asyncio
(如果适用)或threading
模块中的Thread
类,并设置stdout=subprocess.PIPE
来读取输出。
然而,由于subprocess.Popen().stdout
是一个阻塞的流,直接使用可能会遇到问题。一个常见的解决方案是使用io.TextIOWrapper
的readline()
方法,结合循环来逐行读取输出。
示例代码(使用threading
和subprocess.Popen()
):
import subprocess
import threadingdef read_output(proc):for line in iter(proc.stdout.readline, b''):print(line.decode('utf-8').strip())# 创建并启动子进程
proc = subprocess.Popen(['tail', '-f', 'some_log_file.log'], stdout=subprocess.PIPE, text=True)# 启动线程来读取输出
t = threading.Thread(target=read_output, args=(proc,))
t.start()# 注意:这个例子中使用了tail -f来模拟实时输出。你可能需要其他方式来停止线程,
# 比如设置某个标志位,并在read_output函数中检查这个标志位来决定是否退出循环。
5.3 使用环境变量
有时,你可能需要在执行命令时设置或修改环境变量。subprocess.run()
和subprocess.Popen()
都允许你通过env
参数来指定一个环境变量字典。
示例代码:
import subprocess# 设置环境变量
env = os.environ.copy()
env["MY_VAR"] = "some_value"# 执行命令,使用自定义的环境变量
result = subprocess.run(['echo', '$MY_VAR'], shell=True, env=env, text=True)
print(result.stdout) # 注意:在shell=True时,环境变量替换由shell完成,而不是Python。# 如果不想使用shell=True(出于安全考虑),你可能需要修改命令字符串来直接引用环境变量
# 但这通常不适用于动态设置的环境变量,因为命令字符串在Python中就已经被解析了。
# 对于这种情况,你可能需要寻找其他方法来将环境变量传递给命令。
注意:在上面的echo
示例中,由于我们使用了shell=True
,环境变量替换实际上是由shell完成的,而不是Python。这意呀着$MY_VAR
会被shell替换为环境变量MY_VAR
的值。然而,出于安全考虑,通常建议避免使用shell=True
,除非你能确保传递给shell的命令是安全的。
六、总结
在Python中执行Linux命令是一个强大且灵活的功能,可以通过多种方法实现。os
模块提供了基本的命令执行功能,但subprocess
模块因其灵活性和强大功能而被广泛推荐。此外,第三方库如sh
也提供了更加简洁和易于使用的接口。无论使用哪种方法,都需要注意安全问题,并避免命令注入等潜在风险。同时,通过结合异步编程和线程/进程管理等技术,你可以实现更加复杂和高效的命令执行逻辑。