大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
文件系统与权限
这一课你将能做到
- 看懂
ls -l输出的每一段:类型位、rwx 三组权限、链接数、属主/属组、大小、时间、文件名 - 用
chmod数字法(644/755/600)和chown正确设置部署目录、JAR 包、配置文件、日志目录的权限 - 画出 Linux 目录树中与本站相关的关键路径(
/etc、/var/log、/www/wwwroot、~/.ssh),并说出各自放什么
为什么要学
Permission denied 是 Java 后端部署的 第一大报错:服务起不来、日志写不进、JAR 读不了、SSH 密钥被拒——十有八九都是权限。Linux 是多用户系统,每个进程都以某个用户身份运行,「谁能读、谁能写、谁能执行」由文件的权限位决定,不是靠重启碰运气。
本课结束时你要能回答生产高频问题:为什么 JAR 包 root 能读、www 用户起服务却 Permission denied?为什么私钥权限必须是 600 才肯让你用?为什么数据库目录绝不能 777?
先建立图像
一棵树:Linux 只有一个根
没有 C 盘 D 盘,一切从 / 出发:
/
├─ etc/ 所有配置文件(nginx、systemd、ssh…)
├─ var/
│ ├─ log/ 系统与应用日志(排障必来)
│ └─ lib/ 应用数据(MySQL 的数据目录在这)
├─ home/ 普通用户家目录(/home/deploy)
├─ root/ root 用户的家目录
├─ tmp/ 临时文件,重启可能清空
├─ usr/ 系统软件(apt 装的东西多在这)
├─ opt/ 第三方大件软件(自装 JDK 常放 /opt/jdk-17)
├─ www/ 宝塔约定:站点与部署目录(/www/wwwroot)
└─ proc/ 内核暴露的「伪文件」(进程信息等)
一行 ls -l 的完整解剖
-rw-r--r-- 1 www www 52M Oct 6 10:00 backend.jar
│└┬┘└┬┘└┬┘ │ └┬─┘ └┬─┘ └┬┘ └────┬────┘ └───┬───┘
│ │ │ │ │ │ │ │ │ └ 文件名
│ │ │ │ │ │ │ │ └ 修改时间
│ │ │ │ │ │ │ └ 大小
│ │ │ │ │ └────┴ 属组 group(www 组)
│ │ │ │ └ 属主 owner(www 用户)
│ │ │ └ 硬链接数
│ │ └ 其他人 others 的权限:r-- 只读
│ └ 属组 group 的权限:r-- 只读
└ 属主 owner 的权限:rw- 读写;第一位 - 表示普通文件(d=目录,l=软链接)
权限位读法:每三位一组 = r(4) 读 + w(2) 写 + x(1) 执行。rw- = 4+2 = 6。所以:
| 数字 | 权限 | 典型用途 |
|---|---|---|
| 755 | rwxr-xr-x | 目录、可执行脚本(自己全权,他人可进可执行) |
| 644 | rw-r--r-- | 普通文件、JAR 包(自己读写,他人只读) |
| 600 | rw------- | 私钥、密码文件(只有自己能碰) |
| 640 | rw-r----- | 生产配置(属主读写,属组只读,其他人无权) |
| 777 | rwxrwxrwx | 几乎总是错的,等于对全世界开门 |
跟着做
全程在终端敲,建议开个实验目录练习,弄坏了也没负担。
步骤 1:把目录树走一遍
cd / && ls # 根目录长什么样
ls /etc/nginx 2>/dev/null || echo "nginx 未安装,装完再看(包管理课)"
ls /var/log | head -15 # 系统日志区:syslog、auth.log(Ubuntu)
ls ~ # 你的家目录:现在基本是空的
pwd # 确认当前位置
cd - # 回到上一个目录(- 是「刚才那」)
记住两个高频落点:配置在 /etc,日志在 /var/log。排障时人在这两个目录之间来回跑。
步骤 2:读权限——用 ls -l 解剖真实文件
mkdir -p ~/files-lab && cd ~/files-lab
touch a.txt && echo "hello" > a.txt
ls -l a.txt
# 预期输出:-rw-r--r-- 1 ubuntu ubuntu 6 Oct 6 10:00 a.txt
ls -ld ~/files-lab
# 注意目录的权限位是 rwx 开头:目录的 x = 「能否进入该目录」
读法自查:-rw-r--r-- → 普通文件,属主可读写,属组和其他人只读。drwxr-xr-x → 目录,属主可进可改,其他人可进(x)可列(r)。
步骤 3:chmod 数字法实验
chmod 600 a.txt && ls -l a.txt # → -rw------- 只有属主能读写
chmod 755 a.txt && ls -l a.txt # → -rwxr-xr-x 变成了"可执行"
chmod 644 a.txt && ls -l a.txt # → 回到默认
mkdir subdir && chmod 750 subdir # 目录练习:属主全权、属组只进、他人无权
# 符号法(改局部更直观):u=属主 g=属组 o=其他 a=所有人;+加 -减 =设
chmod u+x a.txt # 给属主加执行位
chmod go-w a.txt # 去掉属组和其他人的写权限
ls -l a.txt subdir
步骤 4:chown——把文件「过户」给服务用户
# 生产场景:宝塔/服务常用 www 用户跑 Nginx 和站点。先建实验用户:
sudo useradd -m -s /bin/bash www || true # 已存在则忽略报错
# 模拟部署目录
sudo mkdir -p /www/wwwroot/demo/{logs,conf}
sudo chown -R www:www /www/wwwroot/demo # -R 递归:属主:属组 一起改
ls -ld /www/wwwroot/demo /www/wwwroot/demo/logs
# 验证「过户」效果:用 www 身份去写
sudo -u www touch /www/wwwroot/demo/logs/test.log # 成功,www 能写 logs
sudo -u www touch /www/wwwroot/demo/conf/x.yml 2>&1 # 能否写取决于 conf 权限设置
sudo -u 用户 命令 = 以指定用户身份执行——这是验证权限最直接的办法,比「猜」强一百倍。
步骤 5:权限拒绝的完整复现与修复(部署实况模拟)
# 1) 模拟 root 上传的 JAR,属主是 root
sudo bash -c 'echo fake-jar > /www/wwwroot/demo/backend.jar'
# 2) 用 www 启动服务 → 读取被拒
sudo -u www cat /www/wwwroot/demo/backend.jar
# 预期:cat: /www/wwwroot/demo/backend.jar: Permission denied
# 3) 看属主 → root:root,而其他人对父目录或文件无读权
ls -l /www/wwwroot/demo/backend.jar
# 4) 修复:过户 + 合理权限
sudo chown www:www /www/wwwroot/demo/backend.jar
sudo chmod 644 /www/wwwroot/demo/backend.jar
sudo -u www cat /www/wwwroot/demo/backend.jar # 这次成功,输出 fake-jar
这就是真实部署中「root scp 上传后服务起不来」的标准病因与药方。
步骤 6:文件类型与软链接
ls -l /bin/sh # l 开头:软链接,Ubuntu 里指向 dash
ln -s /www/wwwroot/demo/backend.jar ~/backend-latest # 建软链接(可跨分区,源删了就悬空)
ls -l ~/backend-latest # → l ... backend-latest -> /www/.../backend.jar
cat ~/backend-latest # 通过链接照样读到内容
rm ~/backend-latest # 删链接不影响源文件
软链接在发布策略里很常用:/www/wwwroot/coderoadmap/backend.jar 始终是链接,指向 releases/ 里的真实版本,回滚只需改链接指向。
讲清楚要点
- 权限挂在文件上,判断发生在进程上:每个进程带着自己的 uid/gid 运行,访问文件时内核拿进程身份和文件的属主/属组/其他人三组权限位比对。所以「root 能跑、www 起不来」不是玄学,是身份不同。
- 目录的 x 是「进入权」,w 是「增删权」,r 是「列目录权」:对目录给 r 不给 x,能看名字进不去;给 x 不给 r,进得去但列不了清单——排查「目录明明 755 还进不去」时往父目录的权限找。
- 生产权限三件套:部署目录属主=运行用户(
chown -R www:www);JAR/静态资源 644、目录 755;私钥/含密钥配置 600 或 640。任何 777 都是偷懒埋雷——上传目录要可写,用属主对齐而不是放开所有人。 -R递归是双刃剑:chown -R对了省事、错了灾难(把系统目录属主改掉会让系统罢工)。敲-R前先pwd确认自己在哪。- umask 决定「新建文件的默认权限」:Ubuntu 默认 022 → 文件 644、目录 755。
umask可查可改(写进~/.bashrc持久化),一般不动它。 - 软链接 vs 硬链接:软链接是「快捷方式」(有自己的 inode,可指向目录、可跨分区、源删则悬空);硬链接是「同一文件的两个名字」(同一 inode,不能跨分区、不能指目录)。生产 99% 用软链接。
你可能会懵的地方
- 为什么我明明是 root,文件属主是别人时还会有权限问题?
root 几乎不受权限限制(读、写、chown 都可以),但 执行位为 0 的文件 root 也不能直接执行,且挂载了
noexec/NFS root_squash 等特殊选项时另有规则。见 Permission denied 先看ls -l,别急着怀疑人生。 - chmod 777 为什么是错的?正确做法是什么?
777 让任何用户(包括被攻破的低权限进程)都能改你的文件。正确思路是「最小权限」:先问运行服务的用户是谁,
chown把属主给他,再给 644/755。要「特定其他用户也能写」用组(chgrp + 775)。 sudo到底和权限什么关系? sudo 是「临时借用特权」的机制,与文件权限互补:普通用户默认改不了/etc/nginx/nginx.conf,sudo vim /etc/nginx/nginx.conf是以 root 身份编辑。sudo 详见用户课。- Windows 上写的脚本传到 Linux 报
/bin/bash^M: bad interpreter? Windows 换行是\r\n,多出的\r让解释器路径变成/bin/bash^M。修复:sed -i 's/\r$//' script.sh或用编辑器转为 LF 换行。 - 磁盘没满但「No space left on device」?
可能是 inode 耗尽:海量小文件把 inode 表占满了。用
df -i查 IUse%,通常是大目录里塞了几十万个小文件(如碎片化缓存),找到并清理即可。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
遇到 Permission denied 就 chmod 777 | 安全洞,且掩盖真正的属主问题 | 先 ls -l 看属主,chown 对齐运行用户 |
| root 上传 JAR 后直接启动服务 | 服务用户读不了:Permission denied | 上传后 chown www:www + chmod 644 |
chown -R 在 / 或 /usr 上误敲 | 系统文件属主被改,命令报错成片 | 敲 -R 前先 pwd;养成「先 ls 验证路径」习惯 |
| 日志目录给了 644 | 目录没有 x,进程进不去写不了 | 目录至少 755(或 750+同组),文件 644 |
| 私钥权限 644 还疑惑 SSH 拒用 | ssh 检查到私钥过宽直接拒绝 | chmod 600 ~/.ssh/id_ed25519(SSH 课详解) |
用 rm -rf 清理时路径手误多一个空格 | rm -rf / www 级灾难 | rm 前 ls 确认目标;重要目录用绝对路径且不加尾随空格 |
卡点急救
- 服务起不来,日志报 Permission denied:三步定位——① 确认运行用户(systemd 单元里的
User=或 ps 的第一列);②ls -l看目标文件/目录属主和权限位;③sudo -u 运行用户 cat 文件(读)/touch 目录/test(写)复现验证,然后 chown/chmod 修复。 chmod报 Operation not permitted:只有文件属主或 root 能改权限。加sudo;若连 sudo 都不行,检查是否在只读挂载上(mount | grep ro)。- 删文件报 Permission denied 但文件是 666:删除/创建取决于所在目录的 w+x 权限,不是文件本身的权限。给父目录对运行用户开 w。
- 误把家目录或系统目录 chmod 错了:单文件误改直接改回来;大范围误改且无备份时,Ubuntu 可参考同版本正常机器的权限逐层修复,极端情况重装比修复快——所以
-R之前先备份属主信息:ls -lR > /tmp/perm.bak。
面试常问
-
Linux 文件权限 755、644 分别代表什么? 三组 rwx,r=4/w=2/x=1。755 = rwxr-xr-x,属主全权、属组与他人可读可执行,常用于目录和脚本;644 = rw-r--r--,属主读写、他人只读,常用于普通文件。生产原则:最小权限,杜绝 777。
-
软链接和硬链接的区别? 软链接存的是路径,类似快捷方式:可指向目录、可跨文件系统、删除源后悬空;硬链接是同一 inode 的多个目录项:不能跨文件系统、不能对目录建立,删掉任一名字文件仍存在(直到链接数归零)。日常发布回滚用软链接。
-
如何排查一个进程无法读写某文件? 先确定进程的运行身份(
ps aux | grep 进程第一列或 systemdUser=),再看目标路径的属主与权限位(ls -l,含每一级父目录),用sudo -u 该用户复现验证;必要时namei -l 路径一次性列出整条路径各层的权限。 -
/etc、/var、/opt各放什么?/etc:系统与应用的文本配置(nginx、systemd、fstab);/var:可变数据,重点是/var/log日志与/var/lib应用数据(如 MySQL);/opt:第三方独立软件(自装 JDK、ES 等)。这是 FHS(文件系统层次标准)的约定,跨发行版通用。 -
为什么服务要用专用低权限用户跑,而不用 root? 最小权限原则:服务被入侵或出现 RCE 漏洞时,攻击者拿到的只是该低权用户的能力,写不了系统配置、读不了他人数据;root 进程出漏洞等于整机沦陷。所以 Nginx/Java 服务各用专门用户,配合 systemd 的
User=指定。
自测三问
-rwxr-x---对应的数字是多少?属组用户能对它做什么?- 服务用户
www写日志报 Permission denied,日志目录是/www/wwwroot/app/logs,写出你的排查命令序列。 - 目录的 x 权限和 r 权限分别控制什么?为什么删除一个 666 的文件仍可能被拒?
小结一句话
Linux 用「属主/属组/其他人 × 读/写/执行」三组权限位管住每个文件,判断者是以某个用户身份运行的进程——部署排障时永远先问:这个进程是谁,它碰的文件归谁,权限位给了它什么。
延伸
- Ubuntu 官方文档 — File Permissions
- man 手册:chmod/chown 在线版
- 下一课预告:常用命令——ls/cat 你已会了,但「日志里搜 Exception」「找出占磁盘 40G 的目录」「打包备份 JAR」还差一大批趁手兵器。