Python运行bash脚本报Errno13权限拒绝错误排查方案
问题根因
执行chmod u+x仍触发Errno 13 权限被拒,通常是以下几个原因导致:
- 执行权限加给了错误的用户:
chmod u+x仅会给文件所有者添加执行权限,如果你加权限时用的用户和运行Python脚本的用户不一致(比如root下加权限,普通用户跑Python),当前运行用户依旧没有权限 - 相对路径匹配错误:
./Start_Containers.sh指向的是Python进程运行时的工作目录下的文件,不是Python脚本本身所在目录的文件,如果你从其他目录启动Python,会找不到正确的脚本文件,或者匹配到其他无权限的同名文件 - 目录权限缺失:Linux下要执行目录内的文件,必须对该文件的所有上级目录拥有可执行权限,仅给脚本本身加权限不够
- 跨系统兼容问题:代码里混用了Windows专属API
os.startfile,如果是在Windows/WSL跨环境运行,Windows本身不识别Linux的chmod权限位,直接执行sh脚本必然报错 - 脚本格式错误:如果sh文件是Windows下编辑保存的CRLF换行格式,Linux无法识别开头的shebang行,也会抛出权限类错误
修复方案
按优先级操作即可:
- 绕开脚本执行权限依赖(最稳妥):不要直接执行sh文件,显式调用bash解释器传入脚本路径,这种方式不需要脚本本身拥有可执行权限,从根源规避执行位相关问题。同时不要用相对路径,先通过Python内置方法获取脚本所在的绝对路径,避免工作目录不匹配的问题。
- 修正权限配置:切到运行Python脚本的同一个用户,执行
chmod +x *.sh给所有脚本文件加全局执行权限,避免所有者/用户组不匹配的问题;如果是目录权限问题,给脚本所在目录加可执行权限:chmod +x 你的脚本目录路径。 - 跨环境适配:如果在Windows下开发,要么用WSL环境运行整套代码,要么显式指定Git Bash/WSL的bash程序路径执行脚本,不要用
os.startfile调用sh文件(该API仅支持Windows原生文件关联,Linux/macOS下不存在这个方法)。 - 格式修正:如果脚本是Windows下编辑的,执行
dos2unix *.sh把换行符转成Linux兼容的LF格式。
修正后可运行的核心代码
import os from colorama import Fore import time import subprocess # 初始化时固定获取当前Python脚本所在的绝对目录,避免工作目录漂移 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) START_CONTAINER_SH = os.path.join(BASE_DIR, "Start_Containers.sh") STOP_CONTAINER_SH = os.path.join(BASE_DIR, "Stop_Containers.sh") while True: print(Fore.GREEN + "Welcome\n") print("To Automater") print(Fore.WHITE + """what would you like to do?\n1.Start Containers\n2.Stop Containers\n3.Run A script\n4.Add containers\n5.Exit\n""") choice = input("1-5:\n") if choice == "1": print(Fore.RED + "Starting containers") # 显式调用bash执行脚本,不依赖脚本自身执行权限 subprocess.call(["bash", START_CONTAINER_SH]) elif choice == "2": print(Fore.RED + "Stopping containers") subprocess.call(["bash", STOP_CONTAINER_SH]) elif choice == "3": # 修正原逻辑的问题:仅列出目录下的sh脚本,避免打印所有文件 script_list = [f for f in os.listdir(BASE_DIR) if f.endswith(".sh")] for idx, script_name in enumerate(script_list, 1): print(f"{idx}. {script_name}") elif choice == "4": while True: add_container = input("Would you like to add a container [y/N]") if add_container.upper() == "Y": print("Ok Lets add some") container_name = input("Input container name: ") # 后续补充新增容器的逻辑即可 elif add_container.upper() == "N": break elif choice == "5": print(Fore.GREEN + "Thank you for using Automater") time.sleep(1) break
注:原代码存在两个逻辑bug:一是选项2用了独立的if而非elif,会导致其他选项判断异常;二是输入提示写的是1-4,实际选项有5个,上述代码已经一并修正。
内容的提问来源于stack exchange,提问作者pugnacious unrest
相关产品推荐
相关产品推荐

