Python脚本向/usr/local/bin写入文件遇权限拒绝,如何临时提权并恢复权限?
Python脚本写入
/usr/local/bin权限报错解决方案 核心问题定位
报错根源完全来自目录所有者与执行用户的权限匹配差异,并非权限位显示的格式问题:
/usr/local/bin的原始权限为drwxr-xr-x,所有者是root:对非root用户、非root所属组的普通用户仅开放目录进入、只读权限,不允许新增、修改、删除目录内的文件,所以写入时触发IOError: [Errno 13] Permission denied- 你当前执行脚本的目录
TermTime所有者是当前运行脚本的用户parallels,同样是drwxr-xr-x的权限位,作为目录所有者的你拥有完整的写入权限,所以同一份写入逻辑不会报错 - 你观察到的“读取不报错、写入报错”的现象完全符合上述权限逻辑:
755权限位对所有用户开放读权限,仅写入操作对非所有者用户有限制。
适配无编程基础用户的透明实现方案
整个流程除了需要用户输入一次系统登录密码外,无任何手动配置步骤,所有逻辑在脚本内部完成,对用户完全透明。
首选安全方案(无永久权限变更)
全程不主动修改/usr/local/bin的原始权限配置,通过系统原生sudo机制完成单次提权执行写入,从根源上避免权限被篡改带来的安全风险:
- 普通用户运行脚本时,桌面系统会自动弹出标准的图形化密码输入框,用户输入自己的开机密码即可完成操作,无需在终端手动输入命令
- 提权仅在脚本执行写入的阶段生效,脚本运行结束后自动退出高权限态,不会长期保留root权限
对应适配你原有测试逻辑的可直接运行代码:
import os import sys import subprocess import datetime def write_target_file(): """ 实际写入逻辑,在提权环境下运行 """ target_path = '/usr/local/bin/Test.txt' OUTFILE = open(target_path, 'w') today = datetime.date.today() todayStr = today.strftime('%Y-%m-%d') OUTFILE.write('{0}\n'.format(todayStr)) OUTFILE.close() if os.path.isfile(target_path): print('Successfully wrote the file Test.txt.') else: print('Failed to write the Test.txt file.') # 检测当前是否拥有root权限 if os.geteuid() != 0: # 非root态,自动调用sudo重新运行脚本本身 subprocess.call(['sudo', sys.executable] + sys.argv) else: # 已是root态,执行写入 write_target_file()
可选实现(临时调整权限后恢复)
如果严格按照“临时修改目录权限、写入完成恢复原始状态”的需求实现,必须加入全链路异常捕获,保证哪怕脚本中途崩溃,也能把目录权限恢复到初始值,避免留下安全敞口。
核心执行流程:
- 提权后首先读取
/usr/local/bin的原始权限位、所有者ID、所属组ID,留存备份 - 临时调整目录权限,允许当前进程写入目标文件
- 执行文件写入操作
- 通过
finally代码块强制触发目录状态恢复,不受写入成功/失败、中途异常的影响
对应实现代码:
import os import sys import subprocess import datetime import stat TARGET_DIR = '/usr/local/bin' TARGET_FILE = os.path.join(TARGET_DIR, 'Test.txt') if os.geteuid() != 0: subprocess.call(['sudo', sys.executable] + sys.argv) else: # 留存目录原始状态 origin_stat = os.stat(TARGET_DIR) try: # 临时放开目录的写入权限 os.chmod(TARGET_DIR, origin_stat.st_mode | stat.S_IWOTH) # 执行写入 OUTFILE = open(TARGET_FILE, 'w') today = datetime.date.today() todayStr = today.strftime('%Y-%m-%d') OUTFILE.write('{0}\n'.format(todayStr)) OUTFILE.close() # 校验写入结果 if os.path.isfile(TARGET_FILE): print('Successfully wrote the file Test.txt.') else: print('Failed to write the Test.txt file.') finally: # 无论执行结果如何,强制恢复目录的所有者、权限位 os.chown(TARGET_DIR, origin_stat.st_uid, origin_stat.st_gid) os.chmod(TARGET_DIR, origin_stat.st_mode)
注意:这种临时调整权限的方式存在安全隐患——如果脚本在临时改权后、恢复权限前被强制终止,就会导致
/usr/local/bin的权限被永久放开,所有普通用户都可以修改该目录下的系统可执行文件,存在被恶意利用提权的风险。无特殊需求优先选择第一种提权直接写入的方案。
常见误区澄清
- 权限位显示格式一致不代表权限一致:
drwxr-xr-x的实际生效权限和当前用户的身份强相关,所有者、所属组成员、其他用户对应的权限范围完全不同 - 不要为了省事把
/usr/local/bin的权限永久调整为777、或者把目录所有者改成普通用户:这类操作会破坏系统目录的安全规范,带来长期的安全风险
内容的提问来源于stack exchange,提问作者Barry
相关产品推荐
相关产品推荐

