主题
为什么新建的文件权限是 000
这个坑很邪门:文件明明建出来了,ls 也能看到,名字、大小、时间都对,但打不开。
$ ls -l note.md
---------- 1 app app 4521 Oct 23 07:12 note.md十个横杠。所有者自己都读不了。
什么时候会遇到
我这边的触发场景是:一个跑在容器/沙箱里的进程(身份是独立用户),往宿主机的一个普通目录里写文件。
写完 ls -l 一看,----------。之后任何操作都失败:
$ cat note.md
cat: note.md: Permission denied
$ chmod 644 note.md
chmod: changing permissions of 'note.md': Operation not permitted # 如果连所有者都不是你最坑的是它不报错。写的时候没有任何警告,等你三步之后想 git init、想重新编辑、想让别的进程读的时候才发现。
原因:umask
umask 是"创建文件时要抹掉哪些权限位"的掩码。
正常 shell 里 umask 是 022:
默认文件权限 0666 & ~022 = 0644 → rw-r--r--如果某个进程的 umask 是 0777(或者干脆是 0,取决于语言/框架怎么算),算出来就是:
0666 & ~0777 = 0000 → ----------为什么会有进程用 0777? 常见原因:为了「安全默认」把新建文件设成只有自己(甚至自己也不给)能访问,等显式 chmod 再放开。如果代码路径里少了那一步,文件就永远停在 000。
怎么确认
bash
# 看当前 shell 的 umask
umask
# 看某个进程的 umask(Linux)
grep -i umask /proc/<pid>/status怎么修
1. 补一次权限(最直接)
bash
chmod -R u+rwX,go+rX .为什么用 u+rwX 而不是 u+rwx?大写 X 的意思是「只对目录、以及已经有执行位的文件加 x」。这样目录能进得去,普通文本文件不会莫名其妙变成可执行。
2. 顺手把 umask 设回去
bash
umask 022 # 当前 shell 生效
# 或写进 ~/.bashrc / 服务单元的 UMask=00223. docker cp 出来的文件也要修
docker cp 保留容器内的属主/权限。如果容器里那个文件就是 000(或者属主是容器里的 uid,宿主机上不存在这个用户),拷出来照样打不开。
bash
docker cp container:/app/config.php ./config.php
chmod 644 ./config.php一个判断技巧
ls -ld <目录> 看到:
d--------- 2 app app 4096 ...就知道整个目录都是这个状态 —— 这时候 cd 都进不去,得先 chmod 目录本身。
教训
这件事本质上是**"不报错的失败"**里最典型的一类:命令成功、文件存在、大小非零,唯一的问题是它的元数据不对。
所以现在的习惯是:跨权限边界写文件之后,不要只看"文件在不在",要看 ls -l 的第一列。 尤其是自动化脚本,我会在写完后加一句:
bash
[ -r output.json ] || { echo "文件不可读,检查权限/umask"; exit 1; }比等到十步之后报 Permission denied 强得多。
一句话版本:新建文件不可读,先看
umask,再chmod -R u+rwX,go+rX .;docker cp出来的别忘了补chmod 644。