
Go 中调用 os.Mkdir 时指定的权限位会受系统 umask 影响,实际创建的目录权限是传入值与 ~umask 的按位与结果;若需精确控制权限,需调整 umask 或创建后显式调用 os.Chmod。
go 中调用 `os.mkdir` 时指定的权限位会受系统 umask 影响,实际创建的目录权限是传入值与 `~umask` 的按位与结果;若需精确控制权限,需调整 umask 或创建后显式调用 `os.chmod`。
在 Go 中使用 os.Mkdir("testdir", 0775) 并未如预期生成 drwxrwxr-x(即 0775)权限的目录,而是得到 drwxr-xr-x(0755),根本原因在于 Unix/Linux 系统的 umask 机制:它会屏蔽掉你显式指定的部分权限位。
? 权限计算原理
系统在创建文件或目录时,并非直接应用你传入的 mode,而是执行:
effectiveMode := mode &^ umask
其中 &^ 是 Go 中的“按位清除”操作(即 mode & (^umask))。
例如,若当前 shell 的 umask 为 0022(八进制),其二进制为 000000100010,取反后与 0775(000111111101)按位与:
0775 = 000 111 111 101 ~0022 = 111 111 101 101 (按8位补全后取反) → 结果 = 000 111 101 101 = 0755
这就是为何 0775 被“降级”为 0755。
✅ 解决方案一:创建后显式修改权限(推荐)
无需改动系统环境,安全、可移植、符合 Go 最佳实践:
package main
import (
"log"
"os"
)
func main() {
const dirName = "testdir"
const desiredPerm = 0775
// 先用默认权限创建(umask 不影响后续 chmod)
if err := os.Mkdir(dirName, 0755); err != nil {
log.Fatal("创建目录失败:", err)
}
// 立即修正权限
if err := os.Chmod(dirName, desiredPerm); err != nil {
log.Fatal("修改权限失败:", err)
}
log.Printf("目录 %s 已创建,权限为 %o", dirName, desiredPerm)
}
⚠️ 解决方案二:临时修改进程 umask(慎用)
可通过 syscall.Umask(非跨平台)临时设为 0002,但存在副作用(影响后续所有文件操作),且 syscall 包不保证稳定性,不推荐用于生产环境:
// ❌ 非标准、不可移植、易出错,仅作演示
import "syscall"
syscall.Umask(0002) // 影响整个进程后续所有 I/O
os.Mkdir("testdir", 0775) // 此时才可能得到 0775
? 注意事项
-
os.MkdirAll同样受 umask 影响,多级目录创建也需配合os.Chmod或递归修正; - 权限常量请始终使用八进制字面量(如
0775),避免十进制误写(775≠0775); - 在容器或 CI 环境中,umask 可能被预设为
0022或0002,建议始终以Chmod作为权限兜底手段; - 若需严格遵循 POSIX 行为(如设置 setgid 位),应使用
os.MkdirAll+os.Chmod组合,并确保目标路径不存在。
综上,“先创建、后修正”是最健壮、清晰且符合 Go 语言哲学的权限控制方式。










