使用Python Subprocess执行sudo命令失败,无法修改屏幕亮度求助
解决Python Subprocess调用sudo修改intel_backlight亮度的问题
看起来你遇到的核心问题是sudo权限在subprocess中的正确传递,以及shell命令中重定向的权限陷阱。先帮你分析下之前尝试的代码为什么失败,再给出可行的解决方案。
为什么之前的代码无效?
第一个命令的重定向陷阱:
你写的sudo echo ... > /sys/.../brightness中,sudo只作用于echo命令,而>重定向是由当前用户的shell处理的,并没有root权限,所以无法写入需要root权限的sysfs文件。这就是为什么直接在shell里用sudo bash -c "echo ... > file"能成,但你的写法不行。第二个命令的参数错误:
当使用shell=True时,subprocess期望接收一个字符串命令,而不是列表。你把命令split()成列表再传给Popen,会导致shell解析错误,命令无法正确执行。第三个命令的参数拼接问题:
['sudo', '-S'] + command.split()的写法会把原命令拆成零散的参数,可能导致命令结构混乱,sudo无法正确识别后续的操作。
可行的解决方案
方案1:使用sudo tee(推荐,安全无密码硬编码风险)
tee命令可以接收标准输入并写入文件,配合sudo就能获得写入sysfs文件的权限。这里分两种情况:
情况A:允许代码输入sudo密码
import subprocess # 替换成你的目标亮度值和sudo密码 new_brightness = 600 sudo_password = "your_sudo_pass" brightness_file = "/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight/brightness" # 用列表传递参数,shell=False避免shell注入风险 cmd = ["sudo", "-S", "tee", brightness_file] process = subprocess.Popen( cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True ) # 先输入sudo密码,再输入亮度值,注意都要加换行符 stdout, stderr = process.communicate(input=f"{sudo_password}\n{new_brightness}\n") # 检查执行结果 if process.returncode != 0: print(f"执行出错:{stderr.strip()}") else: print("亮度调整成功!")
情况B:修改sudoers避免输入密码(更安全)
如果不想在代码里硬编码sudo密码,可以修改sudoers文件,让你的用户无需密码就能执行tee修改该亮度文件:
- 执行
sudo visudo打开sudoers编辑器(必须用visudo,避免语法错误) - 添加一行(替换成你的用户名):
your_username ALL=(ALL) NOPASSWD: /usr/bin/tee /sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight/brightness - 保存退出后,代码就可以简化为:
import subprocess new_brightness = 600 brightness_file = "/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight/brightness" cmd = ["sudo", "tee", brightness_file] process = subprocess.Popen( cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True ) stdout, stderr = process.communicate(input=f"{new_brightness}\n") if process.returncode != 0: print(f"执行出错:{stderr.strip()}") else: print("亮度调整成功!")
方案2:使用shell=True(不推荐,有shell注入风险)
如果你一定要用shell模式,需要把整个管道命令写成字符串,确保sudo覆盖整个写入操作:
import subprocess new_brightness = 600 sudo_password = "your_sudo_pass" brightness_file = "/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight/brightness" command = f"echo {new_brightness} | sudo -S tee {brightness_file}" process = subprocess.Popen( command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True ) stdout, stderr = process.communicate(input=f"{sudo_password}\n") if process.returncode != 0: print(f"执行出错:{stderr.strip()}") else: print("亮度调整成功!")
总结
- 避免在subprocess中用
sudo echo ... > file的写法,重定向权限不属于sudo。 - 优先使用
shell=False+列表参数的方式,更安全且不易出错。 - 最推荐的做法是修改sudoers文件,彻底避免在代码中处理sudo密码。
内容的提问来源于stack exchange,提问作者sandy560
相关产品推荐
相关产品推荐

