Django调用的Bash脚本遇sudo超时挂起问题求助
问题排查与解决方案
核心原因分析
挂起的本质是脚本中的sudo命令在无终端(TTY)的环境下尝试请求密码,但Django进程(通常以www-data或其他系统用户运行)没有交互式终端,导致命令阻塞等待输入;且因为没有TTY,密码请求的提示无法输出到日志文件中。
另外你观察到的两个进程是正常现象:os.system()默认会调用sh -c执行命令,所以会出现sh -c bash_script.sh和脚本本身的/bin/bash bash_script.sh进程,和挂起问题无关。
排查步骤
- 定位挂起的sudo命令:在脚本中每个
sudo命令前后添加日志输出,比如:
运行后查看echo "Starting sudo command: [具体命令]" >> /tmp/sudo_debug.log sudo [具体命令] echo "Completed sudo command: [具体命令]" >> /tmp/sudo_debug.log/tmp/sudo_debug.log,最后一条日志对应的就是挂起的sudo命令,确认该命令确实需要sudo权限。 - 验证Django用户的sudo权限状态:切换到Django运行的用户(如
www-data),执行:
如果返回非0值,说明该用户没有免密sudo权限,且当前无有效sudo会话,这就是挂起的直接原因。sudo -n true
解决方案
方案1:配置免密sudo(推荐,最稳定)
彻底避免交互式密码请求:
- 用
visudo编辑sudoers文件(必须用这个命令,防止语法错误破坏sudo功能):sudo visudo - 添加以下内容(替换
www-data为你的Django运行用户,/path/to/bash_script.sh为脚本绝对路径):www-data ALL=(ALL) NOPASSWD: /path/to/bash_script.sh # 若需要更精细控制,可只允许脚本中的特定命令: # www-data ALL=(ALL) NOPASSWD: /usr/bin/apt, /usr/bin/systemctl - 保存退出后,切换到Django用户测试:
确认无需输入密码即可完整运行。su - www-data sudo /path/to/bash_script.sh
方案2:预先生成sudo会话(临时应急)
如果无法配置免密sudo,可在调用脚本前生成有效sudo会话:
修改Python调用代码,先执行sudo -v获取会话,再运行脚本:
import subprocess # 先获取sudo会话(需确保Django用户可无TTY执行sudo -v,部分系统需额外配置) subprocess.run(["sudo", "-v"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # 再运行脚本并记录日志 with open("bash_log.log", "w") as log_file: subprocess.run(["./bash_script.sh"], stdout=log_file, stderr=subprocess.STDOUT, check=False)
注意:此方式依赖sudo超时设置,会话过期后仍会出现挂起,稳定性不如方案1。
方案3:用pty模拟终端(不推荐,仅作极端应急)
若必须输入密码,可通过pty模块模拟终端传递密码,但明文存储密码存在严重安全风险,禁止生产环境使用:
import pty import os def run_sudo_script(script_path, password, log_path): def read(fd): data = os.read(fd, 1024) if b"[sudo] password for" in data: os.write(fd, password.encode() + b"\n") return data with open(log_path, "w") as log_file: pty.spawn(["./bash_script.sh"], read) run_sudo_script("./bash_script.sh", "你的sudo密码", "bash_log.log")
无效方案的原因解释
- 脚本中添加
sudo -v无效:脚本运行时处于无TTY环境,sudo -v同样会阻塞请求密码,无法刷新会话。 - 延长sudo超时无效:Django进程的环境和你手动ssh的环境是独立会话,超时设置不共享,手动延长的是你自己的会话,对Django进程无效。
- 拆分脚本多线程无效:挂起根源是sudo需要终端,拆分后第二部分的sudo命令依然处于无TTY环境,所以仍会挂起。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

