背景
最近有个程序需要以 nobody 用户访问 dirA。最开始我直接把目录的所有者和所属组都写成了 nobody:
chown -R nobody:nobody dirA
这条命令在一部分 Linux 发行版上可以正常执行,但换到 Ubuntu 后却报错了:
chown: invalid group: 'nobody:nobody'
原因
不同 Linux 发行版对 nobody 用户的默认组命名并不一致。有些系统使用 nobody:nobody,Ubuntu 通常使用:
nobody:nogroup
可以使用下面的命令查看当前系统中 nobody 用户的 UID、GID 和组信息:
id nobody
getent passwd nobody
因此,把组名写死成 nobody 并不具备可移植性。
之前的解决办法
为了兼容不同发行版,我曾经在 Go 代码中通过 user.Lookup("nobody") 查询用户,再取出 UID 和 GID,最后调用 os.Chown:
u, err := user.Lookup("nobody")
if err != nil {
return err
}
uid, err := strconv.Atoi(u.Uid)
if err != nil {
return err
}
gid, err := strconv.Atoi(u.Gid)
if err != nil {
return err
}
if err := os.Chown(path, uid, gid); err != nil {
return err
}
这个办法能用,但如果只是执行部署脚本,其实不需要为此增加一段 Go 代码。
更简单的办法
GNU chown 支持省略冒号后面的组名:
chown -R nobody: dirA
这里的 nobody: 表示:
- 将所有者设置为
nobody; - 将所属组设置为
nobody用户的登录组。
也就是说,在默认组叫 nobody 的系统上,它会使用 nobody 组;在 Ubuntu 上,它会使用 nogroup 组。命令本身不需要关心具体的组名。
冒号不能省略。下面这条命令只修改所有者,原来的所属组会保持不变:
chown -R nobody dirA
验证
执行后可以检查目录的所有者和所属组:
ls -ld dirA
也可以直接查看名称和数字 ID:
stat -c '%U:%G %u:%g' dirA
总结
当目标是把目录递归设置为某个用户及其默认组时,可以使用:
chown -R 用户名: 目录
这次的命令就是:
chown -R nobody: dirA
这样可以避免写死 nobody 用户对应的组名,也不用在业务代码中手动查询 UID 和 GID。