Linux权限、用户与进程管理指令实战

📅 发布时间:2026/10/14 4:21:07
Linux权限、用户与进程管理指令实战
这是Linux基本指令系列第三篇。前两篇把文件与目录操作、文本处理这两条主线捋了一遍这次聊聊权限、用户和进程管理这几块。为什么把这三类放到一起因为它们在日常运维和开发中出现的频率最高而且彼此纠缠权限决定你能对文件做什么进程跑在某个用户身份下用户管理又直接决定权限的归属。很多初学者学到这一块开始犯晕我觉得不是因为命令难背而是没搞明白这些指令背后的系统设计逻辑。这篇文章适合两类人一类是刚学完基础指令、正打算往运维或后端方向走的读者另一类是平时用图形界面居多但想补上命令行短板、遇到权限报错能自己解决的人。我会把常用指令的使用方式、适用场景和容易踩的坑一起讲不会只罗列参数。1. 权限到底在保护什么先看明白 rwx 对文件和目录的差别1.1 身份三元组为什么每个文件都要绑定一个用户和一个组在Linux里每个文件都带两个归属属性所属用户owner和所属组group。系统判断一个人能不能操作某个文件看的不是你是谁而是你的身份落在哪个区间里。一个文件面向三种身份开放权限文件属主User、属组内的成员Group、以及其余所有人Other。这就是常说的 UGO 模型。可以用门禁卡来理解。文件是一间办公室门禁规则分三层业主本人拿万能卡U同一团队的同事拿团队卡G外部访客拿临时卡O。系统检查权限时是有顺序的先看你是不是业主是就直接按业主权限处理不再看后面的不是再看你是不是团队成员是就按团队权限都不满足最后才看访客权限。查看自己当前的身份用id查看当前登录名用whoami查看自己属于哪些组用groups。这三个命令在任何系统上都能跑也是最基础的权限诊断工具。$ id uid1000(frank) gid1000(frank) groups1000(frank),27(sudo),998(docker) $ whoami frank $ groups frank sudo docker这里的 uid 是用户IDgid 是主组ID。一个用户可以同时属于多个附加组比如上面的 frank 就同时属于 sudo 和 docker 两个附加组这就是为什么他能执行某些管理员操作。/etc/passwd文件保存了用户的基本信息/etc/shadow保存密码散列普通用户对后者默认没有任何读取权限这也是后面讲 SUID 时的重要伏笔。1.2 rwx 在文件和目录上含义完全不同这是我见过最多误解的地方一条ls -l的长格式输出里第一列是十位字符第一位表示文件类型后面九位分成三组分别对应 U/G/O 权限。比如-rw-r--r-- 1 frank dev 1234 Jan 1 10:00 notes.txt drwxr-xr-x 2 frank dev 4096 Jan 1 10:01 data第一列第一位是-代表普通文件d代表目录l代表符号链接。后面rw-、r--、r--就是三种身份各自的权限位了。关键问题是r、w、x 在文件上和目录上的含义不一样。文件这里的 r 是读取内容w 是修改内容x 是执行但目录上的这三个位含义完全不同很多新手在这里栽过跟头。权限位作用于文件作用于目录r读取文件内容cat、less、tail列出目录项ls但能否进入目录还要看 xw修改文件内容vi、echo 重定向在目录内新建、删除、重命名文件或子目录x执行文件脚本、二进制程序进入目录cd并通过路径访问目录内文件目录没有 x 权限会怎样你能ls看到文件名但cd进不去也没有办法访问目录里任何文件。目录没有 w 权限会怎样你可以在里面读写已有文件前提是文件本身权限允许但不能新建或删除文件。这是很容易混淆的一点删除一个文件的权限取决于文件所在目录的 w 权限而不是文件本身的 w 权限。在实操中这个逻辑有很多直接应用。比如一个 Web 项目目录通常做法是目录给 755文件给 644属主是运行 Web 服务的用户。这样属主能写其他人只能读和执行防止别人通过 Web 漏洞往目录里塞文件。反过来如果一个目录被设成 777任何用户都能在里面创建和删除文件那整个目录的安全性基本等于零。我见过有人在项目根目录直接chmod -R 777图省事结果权限系统形同虚设这是最典型的反面教材。2. chmod 与 umask数字法、符号法和默认权限的隐性坑2.1 数字法为什么是 4、2、1以及递归改权限的正确姿势chmod 是修改权限的核心指令最常见的是数字法也就是chmod 755 file这种写法。很多初学者一开始不理解为什么是 4、2、1 这三个数其实如果你把 rwx 看成三个二进制位一下就通了。r 对应 100二进制就是 4w 对应 010 就是 2x 对应 001 就是 1。把三个位的数值加起来就能表达任意组合。比如 rwxr-xr-x分成三组算rwx 421 7r-x 401 5r-x 401 5合起来就是 755。同样 rw-r--r-- 就是 644。chmod 755 script.sh # 属主可读写执行组和其他人只读执行 chmod 644 notes.txt # 属主可读写组和其他人只读 chmod 600 .ssh/id_rsa # 私钥只允许属主读写这是安全基线 chmod 700 ~/.ssh # 目录只允许属主进入数字法最实用的一点是看到ls -l的输出你能反推权限值反过来也一样。排查权限问题的时候我经常直接在脑子里算一遍十进制。递归修改是一个常见坑点。chmod -R 755 dir会把目录下所有文件和目录统一改成 755但目录和文件的语义不一样通常我们想要的是目录 755能进入能列出普通文件 644只读即可。如果用了chmod -R 777或者chmod -R 755要么太松要么给所有脚本文件都加了执行位属于不该有的权限外溢。更稳妥的做法是分开处理用 find 把目录和文件筛出来分别改find /path/to/project -type d -exec chmod 755 {} find /path/to/project -type f -exec chmod 644 {} -type d只匹配目录-type f只匹配普通文件{} 是把结果一次性传给 chmod执行效率比-exec chmod 755 {} \;高不少。这个方法在批量修正权限时特别可靠我处理线上项目的目录权限时都会用这一套而不是无脑 -R。2.2 符号法适合微调umask 则决定了新建文件和目录的出生权限符号法用u、g、o、a表示身份、-、表示增加、移除、设为指定权限后面跟上 rwx 中的若干位。它适合做局部调整比如给属主加执行权限、给组去掉写权限chmod ux run.sh # 给属主加执行位 chmod g-w shared.txt # 去掉组写权限 chmod or secret.log # 其他人只读不读不执行 chmod ax deploy.sh # 所有身份都加上执行位和数字法相比符号法不用记住最终形态先ls -l看一眼然后只改要改的那一位更安全。我的习惯是新建文件时知道要什么结果直接用数字法在已有文件基础上微调用符号法避免误伤其他权限位。umask 是另一个常被忽略但直接影响日常操作的东西。你可以把它理解为默认权限的遮罩。创建文件时系统默认文件权限是 666rw-rw-rw-目录是 777rwxrwxrwx但会跟 umask 做一个按位取反再与的运算最终结果就是文件真实的初始权限。用最常见的 umask 022 来举例文件是 666 减去 022 得到 644目录是 777 减去 022 得到 755。也就是说你每次创建新文件默认就是 rw-r--r--新目录默认是 rwxr-xr-x。如果 umask 是 077那么新文件是 600新目录是 700只有你自己能碰。$ umask 0022 $ touch newfile $ mkdir newdir $ ls -ld newdir newfile drwxr-xr-x 2 frank dev 4096 Jan 1 10:05 newdir -rw-r--r-- 1 frank dev 0 Jan 1 10:05 newfile需要注意两点。第一为什么新建文件默认没有执行位这是安全设计防止你一创建文件就得到一个可执行脚本降低误执行风险需要执行权限时再手动 chmod。第二umask 是 shell 的内建状态不是系统级的重启或新开终端后需要重新加载。想长期生效就写进 shell 的配置文件比如~/.bashrc或~/.profile里加一行umask 027。不同团队对 umask 的偏好差异很大有的选 022 方便共享有的选 027 更保守有的选 077 强调隔离取决于目录的共享需求。3. chown、特殊权限与属主陷阱谁拥有文件比权限本身更关键3.1 chown 与 chgrp数据目录的属主设置是运维翻车高发区权限位只是规则真正决定谁是主人的是属主和属组这也是 chown 和 chgrp 存在的意义。chown 修改属主chgrp 修改属组。最常见的用法是同步修改属主和属组chown frank:dev notes.txt # 属主改为 frank属组改为 dev chown frank notes.txt # 只改属主 chown :dev notes.txt # 只改属组等价于 chgrp dev notes.txt chgrp dev notes.txt # 同样是改属组 chown -R frank:dev /data/app # 递归修改整个目录树的归属这里有一个容易被历史命令误导的点。旧版本的 chown 支持用chown frank.dev notes.txt这种点分写法现在虽然某些系统还兼容但新代码一律建议用冒号user:group因为点号可能与主机名场景冲突。凡是新写的脚本统一用冒号就好。为什么属主比权限位更关键因为权限位是规则而属主决定规则怎么套。一个典型的翻车场景是把某个应用的数据目录 chown 成了 root但应用本身以普通用户运行之后应用发现自己写不了自己的数据只能临时去改权限位或者重新 chown。真正好的习惯是应用目录的属主必须是运行该应用的那个用户而不是 root。用 root 启动 Web 服务然后让应用去写文件是非常不推荐的姿势因为一旦应用被攻击攻击者拿到的就是 root 权限。更灾难的操作是chown -R用错目标。比如手一抖把chown -R frank:dev /这种命令敲下去系统上所有文件属主都变了后果是系统直接半瘫痪。我自己处理过一次类似事故的善后那种场景下几乎没有快捷恢复手段只能从备份或快照回滚。所以凡是带-R的 chown 或 chmod执行前先pwd确认路径再ls -ld看一眼目标多花五秒钟省掉的是一整天的恢复时间。3.2 SUID、SGID 和 Sticky Bitls -l 里那些 s 和 t 到底代表什么除了 rwx 之外Linux 还有三个特殊权限位SUID、SGID 和 Sticky Bit。它们平时不容易见到但一旦出现往往对应着系统安全中需要重点关注的逻辑。先看 SUIDSet User ID。普通用户修改密码用的passwd命令有权限这么干靠的就是 SUID。你可以用ls -l /usr/bin/passwd看一下它的权限位是-rwsr-xr-x注意属主那一组的 x 位变成了 s这说明这个文件带有 SUID。普通用户执行它时进程的有效身份会临时变成文件属主也就是 root从而能写/etc/shadow。如果没有 SUID普通用户根本不可能修改自己的密码。$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 59976 Nov 12 2024 /usr/bin/passwd用chmod us file可以给文件设置 SUID对应的数字法是 4 开头比如chmod 4755 file。但这里有很多禁忌。第一不要给 vim、bash 这类能够改文件的程序乱加 SUID否则任何执行它的用户都能以 root 身份写文件等于把系统裸奔。第二SUID 对 shell 脚本无效只有二进制可执行文件能可靠地使用 SUID脚本的 SUID 位在很多系统上会被忽略还会带来安全隐患。如果你需要让某个普通用户以特定身份执行一个固定操作正确做法不是加 SUID而是用 sudo 配置授权。SGIDSet Group ID分两种情况。对二进制文件类似 SUID但改变的是有效组身份对目录SGID 有更常见的应用目录设置了 SGID 后任何人在里面新建的文件属组自动继承目录的属组而不是创建者自己的主组。这对于团队共享目录特别有用配合相关权限位可以实现谁都能写但文件始终归项目组所有的效果。命令是chmod gs dir数字法是 2 开头比如chmod 2770 shared_dir。Sticky Bit 则主要用在/tmp这类公共目录。/tmp的权限是drwxrwxrwt最后的 t 就是 Sticky Bit。它的作用是目录对所有人开放写权限但用户只能删除属于自己或者自己拥有的文件不能随手删别人的。如果去掉这个位一个多用户系统的 /tmp 会变成一个谁都可以互相删文件的混乱现场。设置 Sticky Bit 用chmod t dir数字法是 1 开头比如chmod 1777 /tmp。想审计系统里哪些文件开了 SUID可以执行find / -perm -4000 -type f 2/dev/null-perm -4000表示只要有 SUID 位就匹配。这个命令建议在全新安装的系统上跑一次留个底以后定期对比。如果哪天多出了一个不该有的带 SUID 的诡异文件那就要警惕了这通常是系统被入侵的典型信号之一。4. 进程与用户管理的日常高频指令从 ps 看到 kill从 useradd 到 sudo4.1 ps 与 top先看清进程在干什么再决定怎么处理进程管理的第一步不是 kill而是看。ps是最基础的进程查看命令两个最常见的派系是ps aux和ps -ef。它们想表达的内容差不多都是列出所有进程的详细快照区别只是输出字段格式略有不同。我自己的使用习惯是ps aux因为字段更直观USER、PID、CPU 占用、内存占用、VSZ、RSS、TTY、STAT、START、TIME、COMMAND 一列排开。$ ps aux | head -5 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.2 102204 14836 ? Ss Jan10 0:41 /sbin/init frank 1204 0.0 0.5 146532 30012 ? S 11:00 0:15 /usr/bin/gnome-shell frank 1450 0.3 0.1 204532 8764 ? Sl 11:01 1:09 /usr/lib/firefox/firefoxSTAT 这一列代表了进程状态非常重要R 表示正在运行S 表示可中断睡眠正常等待状态D 表示不可中断睡眠通常在等磁盘 I/OT 表示已停止Z 表示僵尸状态。如果你的系统里出现大量 D 状态进程先检查磁盘如果出现 Z 状态进程那说明有进程还没被父进程回收需要关注。僵尸进程是很多新手问过的问题。它其实已经不是活跃进程了只是进程表里还保留着一条代表我已退出等父进程来收尸的记录。正常情况下父进程会调用系统接口回收它但如果父进程自己写得有问题或者卡住了僵尸进程就会一直留着。单个僵尸不用太紧张关键看数量如果越来越多通常要处理的是它的父进程kill父进程或让父进程重启僵尸才能被系统回收。用pstree -p可以直观看到进程父子关系定位到谁生出了这个僵尸。top是动态视图刷新进程状态用的。启动后按P按 CPU 排序按M按内存排序按k可以输入 PID 杀进程按q退出。如果觉得安装替代品没问题htop体验更好但生产环境不保证有top是底线技能。排查 CPU 飙升问题时我的固定流程是先top按 P 排序确定可疑进程再用ps -fp PID查看它的完整命令行判断是不是合法进程最后再决定处理手段。只看进程名是不太够的因为同名进程可能很多且恶意程序常把进程名伪装成正常名字结合ls -l /proc/PID/exe看它实际执行的程序路径是更可靠的验证方式。4.2 kill 与作业控制不要上来就 -9给进程一个体面退出的机会向进程发送信号通常用 kill但它真的不只是杀死进程。kill做的只是向进程发送一个信号默认信号是SIGTERM也就是 15。收到 SIGTERM 的进程可以自己处理收尾工作比如保存配置、释放资源、关闭连接然后再退出。这就像让人下班前自己关好电脑是一种体面的退出方式。kill -9发送的是SIGKILL进程没有机会做任何收尾直接消失。对大部分正常服务上来就 -9 是粗暴且有害的数据库可能没来得及落盘文件可能写到一半进程清理函数根本没跑。所以排查问题时我的习惯是先kill pid也就是 kill -15等几秒看进程是否退出没反应再kill -9。有些场景确实必须 -9比如进程已经彻底卡死或者状态不可中断且无法正常响应信号但那是最后手段不是默认手段。kill 12345 # 发送 SIGTERM优雅退出 kill -9 12345 # 发送 SIGKILL强制退出 killall nginx # 按进程名发送信号所有叫 nginx 的进程都会收到 pkill -f python app.py # 按命令行匹配进程注意 -f 会匹配完整命令行慎用 pgrep -la ssh # 只列出匹配 PID 和进程名适合在执行 kill 前做确认pkill -f是双刃剑。它匹配的是完整命令行很方便但也可能误杀很多看起来不一样的进程。我见过有人写pkill -f java结果把其他包含 java 字样的进程全带走了。用之前先pgrep -f看一眼匹配结果再动手。作业控制这块命令行后台化也是常用技能。普通程序跑起来占住终端的时候可以按CtrlZ把进程挂起bg放到后台继续跑fg再拉回前台。如果想让命令完全不受关闭终端影响用到的是 nohup 和nohup python server.py server.log 21 这里让命令在子 shell 后台执行nohup让进程忽略挂断信号 server.log 21把标准输出和错误输出都重定向到日志文件。这样即使你关闭终端进程也会继续跑。用jobs -l可以查看当前 shell 的后台任务但需要注意jobs只管理当前终端会话的任务一旦终端退出任务就和这个 shell 断开了想管它就得用ps重新找 PID。4.3 用户管理的常见组合useradd、passwd、usermod 的正确用法用户管理这块日常高频的是新增用户、设密码、加组、授权这四个动作。新建用户的典型命令是useradd -m -s /bin/bash -G sudo dev passwd dev-m创建家目录-s指定登录 shell-G指定附加组。这里有个发行版差异要记住有些系统默认给 useradd 建家目录有些默认不建所以跨发行版操作时建议显式加-m省得后来发现用户没有家目录。passwd dev是为用户设置或修改密码根据系统策略可能需要满足最小长度和复杂度要求。usermod 最常用来修改用户属性但有一个参数错误会导致连锁问题-G是覆盖附加组-aG是追加附加组。很多人一开始没看清楚直接把用户追加到某个新组用了usermod -G docker dev结果 dev 原有的 sudo 组被覆盖掉了用户一下子丢了管理员权限。这个问题我有段时间被反复问原因基本都是这个参数。正确做法是追加用-aGusermod -aG docker dev主组用-g修改附加组用-G和-aG修改这两个概念要分清楚。查看用户当前属于哪些组groups dev即可。创建组用groupadd把用户加入既有组也可以用gpasswd -a dev docker。再来说 su 和 sudo。su dev是切换到 dev 用户但仍保留当前用户的环境变量和工作目录容易引起环境错乱su - dev是完整登录式切换会加载目标用户的完整环境。sudo则是用授权的方式执行单条命令把管理员能力按命令粒度下放。两者的安全性差异在于su 需要目标用户的密码共享 root 密码本身就是高风险操作sudo 使用当前用户自己的密码而且可以通过配置文件精确控制某人能执行什么命令不能执行什么。sudo -l # 查看当前用户有哪些 sudo 权限 sudo visudo # 编辑 sudoers 配置文件注意必须用 visudo不要直接手改sudo 的配置文件在/etc/sudoers任何改动都建议用visudo打开因为它会做语法检查避免你改出一个语法错误把自己锁在管理员权限之外。常见的授权写法是让某个用户组的人能执行所有管理员命令比如%sudo ALL(ALL:ALL) ALL这行意味着 sudo 组的成员可以以任何用户身份执行任何命令。实际工作中最小权限原则更值得提倡只授权必要的命令而不是无脑给所有权限。这里再补一句和前面权限内容的衔接。新建用户之前先想清楚这个用户要不要家目录、要不要能登录 shell、要不要有 sudo 权限建好用户后用id确认归属用sudo -l确认授权范围。用户管理里的少给权限、确认无误再扩大授权这个原则和文件权限里的宁可收紧、不要无脑 777是完全一致的说到底都是把系统的默认信任边界收紧到最小。