runuser 命令详解
更新时间:2026-09-17。「一个命令一个文档」系列,属于用户与权限族。当你已经是 root(root 脚本、开机任务、容器 entrypoint)要降权成普通用户跑命令时,runuser 比 su/sudo 更直接。
一、常用法
bash
runuser -u app -- /opt/app/server # 以 app 身份跑命令(root 执行,无需密码)
runuser -u app -w PATH -- ./script.sh # 继承指定环境变量
runuser -l app # 起 app 的登录 shell(读其 profile)
runuser -l app -c 'whoami && id' # 登录环境执行命令串
runuser -u app -g app -G docker -- id # 指定主组/附加组
runuser -u app -- env # 看降权后的环境-u 用户:目标用户;后面用--分隔要执行的命令。-l/--login:模拟登录 shell,切换到其家目录并加载 profile;不加则保持当前目录、环境最小化。-g/-G:主组/附加组;-w VAR1,VAR2:保留变量。
二、和 su / sudo 的区别(核心)
| 维度 | runuser | su | sudo |
|---|---|---|---|
| 谁能用 | 仅 root | 任意用户(一般要目标密码) | 授权用户(要自己的密码/免密) |
| 是否认证 | 不需要密码、不做 PAM 认证 | 需要目标用户凭据 | 按 sudoers 鉴权 |
| 开销 | 轻(不切 PAM 会话) | 走 PAM | 走 PAM/sudoers |
| 典型场景 | 已是 root 的脚本/服务降权 | 交互切换用户 | 授权提权 |
关键定位:runuser 是"我已经是 root,不需要再被认证,直接换个 uid 跑"。它不能用来提权(非 root 运行直接失败),也正因如此 root 自动化脚本里不会卡在密码/PAM 上。
三、典型场景与坑
- systemd/启动脚本降权:root 的初始化脚本做完特权操作(绑低端口、挂盘)后,用
runuser -u app -- server以非特权身份拉起服务。不过 systemd 单元更推荐直接写User=app/Group=,由 init 管理更干净。 - 容器 entrypoint:root 入口做 chown/初始化后
exec runuser -u app -- ...(或 gosu/su-exec,后者不产生中间进程)。 - 环境变量丢失:不加
-l时只保留少量安全变量;应用依赖的 PATH/HOME/JVM 变量要显式-w或在命令里env VAR=x,否则"root 能跑、app 跑报找不到命令"。 - 当前目录:默认不切家目录,可能停在普通用户无权限的目录;需要时加
-l或命令里先cd。 - 注意
-c是把字符串交给 shell 解释,要防注入;自动化优先runuser -u app -- /绝对路径 参数的直接形式。
相关命令
交互切用户用 su,授权提权用 sudo,确认身份用 id/whoami,服务内降权优先用 systemd 的
User=,容器场景可对比 gosu/su-exec。
总结
runuser -u 用户 -- 命令 让已经是 root 的调用方免密码、不经 PAM 直接换 uid 执行:-l 模拟登录环境、-g/-G 指定组、-w 保留变量;它专为 root 脚本/开机/容器场景"降权"设计,不能用于提权,与需要认证的 su(要目标密码)和按 sudoers 鉴权的 sudo 形成分工;注意默认环境最小化、不切家目录,systemd 里更推荐直接用 User=。