前两篇把文件和目录的常用操作梳理了一遍,这篇接着往下走,围绕大家问得最多的四块内容展开:用户与用户组、权限体系、打包压缩、进程与服务。我特意把这四块放在一起讲,是因为它们在日常操作里是强关联的——接手一台新服务器,你要先建用户、配权限,再部署代码、起服务,中间必然要跟压缩包打交道,最后还要确认进程是否正常跑起来。这正好是一条完整的运维链路,比孤立地记命令实用得多。
1. 用户与用户组:几个命令解决“多人共用一台机器”的权限问题
先说个我常被问到的点:在 Linux 下新建用户,到底该用 useradd 还是 adduser?网上答案五花八门,有人说这俩没区别,有人说必须用 adduser。实际上两者的关系很简单——adduser 是 CentOS 系(准确的说是 Red Hat 系)对 useradd 做的一个交互式封装,但 Debian/Ubuntu 系的 adduser 则是一个独立的 Perl 脚本,行为跟 useradd 很不一样。大多数生产环境脚本里,大家都直接写 useradd,因为它参数固定、行为可预期,这是我喜欢它的最重要原因。
1.1 useradd 的默认值与真实参数
很多刚接触 Linux 的人跑完 useradd 用户名 之后,就以为完事了,结果一 su 切换过去发现连主目录都没有,环境变量也怪怪的。这是因为 useradd 的默认行为刻意保持了精简——它不会自动创建 home 目录,也不会帮你复制 /etc/skel 下的骨架文件,更不会设置密码。
实际建用户,我至少会用上这几个参数:
bash复制useradd -m -d /home/zhangsan -s /bin/bash -G wheel zhangsan
-m:同时创建用户主目录,并把/etc/skel下的默认配置复制过去-d:指定主目录路径-s:指定登录 shell,默认可能是/bin/sh,没特殊需求我还是建议显式切到 bash-G:把用户加入附加组,比-g(指定主组)更常用,因为一个用户通常需要同时属于多个组
这里有个容易踩的坑:如果你用 useradd 建完用户后直接登录,会卡在密码验证。因为 useradd 默认不设置密码,用户处于锁定状态。必须再执行 passwd zhangsan 来设密码,或者在 useradd 后紧跟一句:
bash复制echo "zhangsan:初始密码" | chpasswd
另外,确认用户是否建好,不要靠猜。我习惯用 id zhangsan 看 uid/gid 和所属组,用 finger zhangsan(如果装了的话)看用户详细信息。注意 uid 会直接决定用户对文件的初始归属判断,后面在权限章节会用到。
1.2 用户组的增删改:groupadd / groupdel / usermod
用户组本身不复杂,核心命令就三个:
bash复制# 新建组
groupadd dev
# 把已有用户加入组(注意是 -aG,-a 表示追加,不加会覆盖原有附加组)
usermod -aG dev zhangsan
# 删除组
groupdel dev
提示:
usermod -G如果忘了-a,会把用户清出所有其他附加组,相当于“踢出了所有群”。在批量改权限的脚本里真的很容易翻车,务必记住追加是-aG而不是-G。
删除用户用 userdel,默认只删用户本身,主目录和邮件池都会留下。想连主目录一起清理,用 userdel -r 用户名。注意:如果用户还有进程在跑,userdel 会提示“user is currently used by process xxxx”,这时候要么先 kill 进程,要么用 -f 强制删除,但我一般不建议强删,容易留下幽灵文件。
1.3 用户切换与提权:su 和 sudo 的细节
多用户系统里,“用谁的身份执行命令”是每天都要面对的问题。最基本的:
bash复制su - zhangsan # 切换到 zhangsan 并加载其完整环境(注意 - 参数)
sudo command # 用 root 权限执行命令
sudo -i # 切换到 root 的完整登录环境
面试里常考 su 和 su - 的区别:前者只切换用户身份,不加载目标用户的环境变量;后者连 PATH、HOME 这些都会切换到目标用户。日常排障时我几乎只用 su -,因为有些工具依赖 PATH 里特定目录,少了 - 会出现“命令明明装了却找不到”的假象。
sudo 的配置集中在 /etc/sudoers,不推荐直接编辑,官方做法是用 visudo 命令修改——它会做语法检查,阻止你写出一份让 sudo 崩溃的配置。常用的给用户授权规则是:
bash复制# 给所有 wheel 组用户完整的 sudo 权限
%wheel ALL=(ALL) ALL
# 只允许用户执行特定命令
zhangsan ALL=(ALL) /bin/systemctl, /usr/bin/docker
限制单条命令的做法在生产环境中非常普遍,可以尽量避免“一给就给 root 所有人”的粗放管理。我个人习惯把需要 sudo 的用户都加入 wheel 组,然后在 sudoers 里限制职责范围,既灵活又可控。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 权限体系:rwx 权限位、umask 和“最小权限原则”
权限是 Linux 新手最容易晕的部分,但也是面试几乎必问的部分。可能有人觉得“用 root 就是干,权限跟我没关系”——等你一旦部署过 Web 服务、跑过 Docker、或者多人共用一台开发机,就知道权限设计理解不到位会引发多少莫名其妙的线上问题。最经典的场景就是:站点目录权限 777,任何用户都能改,结果被人传了后门,你还不知道哪来的。
2.1 权限位的基本模型
Linux 对每个文件/目录记录三种权限:读(r=4)、写(w=2)、执行(x=1),分别作用于三类主体:属主(u)、属组(g)、其他(o)。一个文件权限通常写成 -rwxr-xr-- 这种形式,拆开看就是:
text复制- rwx r-x r--
类型 属主 属组 其他
对于目录,权限的含义略有区别:读权限决定你能不能列出目录内容;写权限决定你能不能在该目录下新建/删除文件;执行权限决定你能不能 cd 进去。很多人容易忽略目录的写权限——如果只给了读和执行,你能 ls、能 cd,但创建不了文件,这在项目交付时经常成为问题源头。
计算上,权限位其实就是一个 4+2+1 的数字系统。rwx 是 7,r-x 是 5,r-- 是 4。这套八进制表示法在命令里用得最多。
2.2 chmod 的两种姿势:符号模式与八进制模式
改权限最常用的是 chmod。有两种写法,我都建议掌握:
bash复制# 符号模式
chmod u+x script.sh # 给属主加执行权限
chmod g-w,o-r file.txt # 去掉属组的写权限、其他的读权限
chmod a+r file.txt # 所有人加读权限
# 八进制模式
chmod 755 script.sh # rwxr-xr-x
chmod 644 file.txt # rw-r--r--
chmod 700 private_dir # rwx------
八进制模式在脚本里可读性更强,但符号模式在处理“只改一种身份、保持其他不变”的场景时更好用。我的经验是:服务器上的关键脚本统一使用八进制写法,因为一眼就能看出权限位是什么。
这里必须重点强调一个新手最容易犯的错误:对整个目录递归执行 chmod -R 777。这确实能解决几乎所有权限报错,但副作用是让任何用户都能篡改文件。正确思路是:先看文件需要什么权限,再缺什么补什么。比如 Web 目录需要 PHP 写 session,那就只给 www 用户写权限,而不是给全世界。
2.3 chown 和 chgrp:修改属主的边界
改属主比改权限位更需要谨慎。命令很简单:
bash复制chown zhangsan:dev app.log # 同时改属主和属组
chown -R zhangsan:dev /data # 递归修改整个目录
chgrp -R dev /data # 只改属组
需要注意的点是:chown 递归修改非常危险。你原以为目标目录只有项目文件,结果里面挂载了一个别的数据目录,递归下去会把那块分区属主也改了,导致其他服务启动失败,且排查方向极易跑偏。所以我对所有递归变更操作的统一建议是:先确认目录边界,用 ls -la 看一遍,再动手。
2.4 umask:决定“默认权限”的隐藏开关
每次创建文件时,初始权限不是 666/777,而是拿这两个值减掉 umask。Linux 默认 umask 一般是 022,所以:
- 新建文件:666 - 022 = 644
- 新建目录:777 - 022 = 755
这个逻辑让人困惑的地方在于:为什么文件默认没有“执行”位?因为普通文件默认不应该是可执行的,这符合安全理念。你可以用 umask 命令查看当前值,也可以临时修改:
bash复制umask 077 # 之后创建的文件默认只有属主可读写
如果你希望共享给组内其他用户写权限,可以把 umask 改成 002,这样默认权限是 664/775。这个设计在多人协同时特别有用——避免忘了 chmod g+w 导致协作方只能看不能改。
2.5 特殊权限位:setuid / setgid / 粘滞位
这部分在面试中是加分项,日常使用中也值得掌握。
bash复制# setuid:文件以属主身份执行,典型例子是 /usr/bin/passwd
chmod u+s /path/to/app
# setgid:目录下新建文件自动继承目录属组
chmod g+s /share/dir
# 粘滞位:目录内只有属主/root 能删除自己的文件,典型例子是 /tmp
chmod +t /tmp
面试题常问“/tmp 目录为什么所有用户都能创建文件,却又不能互相删除”,答案就是粘滞位。而 setgid 在共享协作目录里很实用:多个用户共用一个目录,只要目录设置了 setgid,新建的文件自动归入该组,省去反复 chgrp 的麻烦。
3. 打包与压缩:tar 命令、乱码问题与跨平台传输经验
打包压缩这块,很多人觉得无非是“解压跑一下”的事,但你一旦面对二进制部署包、日志归档、跨 Windows 传输的 zip 结构,就会遇到各种基础指令解决不了的问题。尤其是中文文件名乱码——这是热搜词常客,也是我在工作中真实遇到过的频发故障。
3.1 tar:最高频的组合拳
Linux 上最通用的归档工具是 tar,它的参数组合几乎形成了“肌肉记忆”:
bash复制# 打包并压缩
tar -czvf app.tar.gz /data/app
# 解压
tar -xzvf app.tar.gz
# 打包为 tar(不压缩)
tar -cvf app.tar /data/app
# 只看内容不解压
tar -tzvf app.tar.gz
逐个解释这几个字母的含义:c 创建归档,x 解压,z 通过 gzip 压缩,v 显示过程,f 指定文件名(-f 后必须紧跟归档文件名)。如果压缩文件是 .tar.bz2,把 z 换成 j;如果是 .tar.xz,用大写的 J。
有同学记不住到底用 -czvf 还是 -xzvf,其实只要记住“打包是 c,解包是 x”,其他加压缩格式字母就行。提取到指定目录用 -C:
bash复制tar -xzvf app.tar.gz -C /opt/target
注意:tar 解压时如果包内路径带了绝对路径(
/开头)或者../,会有覆盖系统文件的风险。生产环境如果不是特别信任该包来源,建议先tar -tzvf瞄一眼内容路径,再用-C限制输出目录。
3.2 压缩格式怎么选:gz / bz2 / xz / zstd
我自己的选择逻辑很简单:
- 日常备份、源码传输:用
gzip,兼容性最好,压缩速度尚可。 - 大文件归档且不频繁解压:用
xz,压缩率最高,但慢。 - 追求解压速度、机群部署:用
zstd,压缩率和速度都不错,很多新版 Linux 发行版已内置。
来看一个同目录对比的结果:
| 格式 | 命令 | 压缩后大小 | 相对耗时 |
|---|---|---|---|
| gzip | tar -czvf |
约 100MB | 基准 |
| bzip2 | tar -cjvf |
略小 | 更慢 |
| xz | tar -cJvf |
小约 20%-30% | 明显更慢 |
| zstd | tar --zstd -cvf |
接近 xz | 非常快 |
如果你的备份脚本每次都要跑很久,大胆试试 --zstd,这可能是最划算的升级。
3.3 zip / unzip:中文文件名乱码的根因
解压 Windows 传过来的 zip,十有八九会遇到中文文件名乱码。核心原因是:Windows 压缩时默认用 GBK/CP936 编码文件名,而 Linux 默认按 UTF-8 解码,两边对不上,于是文件名变成“锟斤拷”或一堆 ?。
解决方案按场景分:
bash复制# 方案一:unzip 指定编码解压(部分发行版支持)
unzip -O GBK 文件名.zip
# 方案二:用 7z 解压,并指定编码
7z x 文件名.zip -o输出目录
# 方案三:用 Python 脚本统一处理文件内部编码
python3 -c "import zipfile,sys; zipfile.ZipFile(sys.argv[1]).extractall()" file.zip
unzip -O GBK 在很多发行版上并不是默认编译进去的,如果你执行报 “invalid option”,装一下 p7zip 或者用 Python 方案绕一下。Python 方案本质是让 zipfile 模块把元数据按 UTF-8 读取,遇到 GBK 编码名为 UTF-8 时一般会直接乱码,所以我不太推荐在中文 zip 上强行用纯 Python。
我在生产环境处理跨平台交换文件时,标准流程是:
- 先用
file file.zip看压缩包类型和编码信息 - 再决定用
unzip -O GBK还是7z x - 解压后立刻
ls -l检查文件名,确认没有乱码再继续后续操作
3.4 7z 的安装与使用
7z 在压缩率上表现公认不错,尤其在处理大目录或 Windows 生态下的 .7z 包时几乎是唯一选择。安装方式:
bash复制# Debian/Ubuntu
apt install p7zip-full
# CentOS/RHEL
yum install p7zip p7zip-plugins
常用命令很简单:
bash复制7z x 包.7z -o/target # 解压
7z a 归档.7z /data/dir # 压缩
7z l 包.7z # 列表查看
需要注意 -o 后面不能有空格,直接接目录路径。这个细节容易让新手困惑,特此说明。
3.5 打包备份的最佳实践
给目录做备份时,我会额外加两个参数:
bash复制tar -czvf backup_$(date +%F).tar.gz --exclude='backup_*.tar.gz' /data/www
--exclude 参数非常实用——避免把上次的备份打包进新备份,陷入递归备份的尴尬。加上 date +%F 生成带日期的备份文件名,也让后续清理旧备份变得轻松。
4. 进程与系统状态:从 ps 到 top 再到 systemctl 的排查思路
最后一块是这个系列最实战味十足的部分。很多线上问题排查的第一步不是看代码,而是看进程有没有活着、CPU 被谁吃满了、服务什么时候挂的。这几条命令用熟,排障效率至少能翻倍。
4.1 ps 参数:为什么大家都写 ps aux
最常见的进程查看命令写法是:
bash复制ps aux
ps -ef
两者都能列出所有进程,区别在于:
ps aux是 BSD 风格,输出包含 %CPU、%MEM、VSZ、RSS 等信息,更直观ps -ef是 System V 风格,输出更标准,在脚本里解析更稳定
面试里如果问“如何查看某个进程是否在运行”,我推荐组合:
bash复制ps aux | grep 进程名
pgrep -a 进程名
pidof 进程名
grep 的缺点是会匹配到 grep 自己,所以很多人会在 grep 后面再加个排除条件,实际工作中我更喜欢用 pgrep -a 或者 pgrep -l,直接输进程名就能拿到 PID 和命令完整行,干净利落。
4.2 top / htop:实时视图与内存判断
top 是看实时资源的标配命令。进去之后几个键要记住:
P按 CPU 排序M按内存排序k杀掉指定进程q退出
还有个容易误解的指标:load average。三个数字分别代表 1 分钟、5 分钟、15 分钟的平均负载,值高低要和 CPU 核数对比才有意义。一台 4 核机器负载 4.0,意味着每个核心都已经满负荷;负载 2.0 在双核上体验还行,但跑到 8.0 基本就是排队严重了。
top 的界面对于不爱看字符界面的人来说不太友好,所以很多人装 htop,直接用方向键选择进程,F9 杀掉,还带颜色显示内存条。对于服务器上快速排查,top 已经够用;本地调试或调试容器内资源占用, htop 体验更好。
4.3 进程结束与后台任务管理:kill 的层级
杀进程是高风险操作,顺序很重要:
bash复制kill PID # 发送 TERM 信号,请进程自行退出
kill -9 PID # 强制结束,进程来不及清理资源
pkill 进程名 # 按名字杀,需要小心误杀
别上来就用 kill -9。正常流程应该先给进程一个优雅退出的机会,让它自己释放端口、保存状态。只有确认僵死、无响应时才用 -9 强杀。特别提醒:pkill 按名字匹配是模糊匹配,比如 pkill php 会把所有名字含 PHP 的进程全干掉,在有多个项目共存的机器上要格外慎重。
后台任务的场景也很常见:
bash复制nohup ./start.sh > run.log 2>&1 &
这行命令的意思是:用 nohup 启动 start.sh,标准输出和错误输出都写入 run.log,放到后台执行(&)。配合 jobs -l 和 fg 可以管理当前 shell 的后台任务,不过 SSH 断开后还能访问的只有 nohup 启动的进程。
4.4 systemctl:从 SysV 到新时代的服务管理
现在的 Linux 发行版基本统一用 systemd 管服务,日常命令:
bash复制systemctl start nginx # 启动服务
systemctl enable nginx # 设为开机自启
systemctl status nginx # 查看服务状态
systemctl restart nginx # 重启
systemctl stop nginx # 停止
journalctl -u nginx -f # 实时查看服务日志
很多线上故障源于服务没有 enable,机器重启后服务没拉起来。所以我的部署流程里必然包含两个动作:systemctl start 和 systemctl enable,合起来叫“启动并设置开机自启”。
如果一个服务启动失败,排查顺序通常是这样:
systemctl status 服务名看报错信息journalctl -u 服务名 -n 50看最近 50 行日志- 检查端口是否被占用:
ss -tlnp | grep 端口号 - 检查配置文件语法:比如
nginx -t - 确认权限问题:是否没有 PID 目录写权限、SELinux 是否拦截
这套流程基本覆盖了 90% 的服务启动失败场景。
4.5 一个综合排查案例:端口明明监听着,却访问不了
说一个我实际遇到的案例,把上面的知识点串起来。
某天同事反馈“Java 服务在服务器上跑着,但浏览器访问超时”。我上去第一步:
bash复制ps aux | grep java # 确认进程在不在
ss -tlnp | grep 8080 # 确认端口是否监听
firewall-cmd --list-all # 确认防火墙是否放行 8080
curl -I http://127.0.0.1:8080 # 本机访问测试
本机 curl 通了,说明服务正常。再查防火墙,发现端口确实开放了。最后排查到云安全组规则里漏了 8080 的入站规则——这一步不属于 Linux 指令本身,但也说明排查问题时没必要一头扎进配置文件里,先按“进程 -> 端口 -> 防火墙 -> 外部规则”的顺序从近到远扫一遍,往往更快。
5. 面试高频点与进阶方向
既然热词里出现了“linux面试题”“kali linux 学习笔记”“linux 内核 动态加载 file_operations 拦截 read write”“linux 内核 透明加密”这些词,我认为有必要把这部分单独拎出来聊聊。基础指令是“术”,理解了背后的机制才能在面试和实战中稳住。
5.1 真正容易考的基础指令题
如果面试官问“Linux 基本指令”,千万别上来只背命令列表,更常见的是给你一个场景:
- 查看系统负载用什么指令?——
uptime,它会显示 load average - 查看内存使用情况?——
free -h - 查看磁盘空间?——
df -h和du -sh 目录 - 查看文件末尾变化?——
tail -f - 查找大文件?——
find / -type f -size +500M -exec ls -lh {} \;
find 这个命令值得单独练一下,它是 Linux 入门到进阶的一道分水岭。配合 -exec 可以批量执行操作,比如删除三天前的日志:
bash复制find /var/log -name "*.log" -mtime +3 -exec rm {} \;
5.2 从指令到系统机制:uid/gid 与文件系统
面试官一旦深挖,往往会从“新建一个用户”引申到“这个用户的 UID 是怎么分配的,和文件系统权限有什么关系”。此时你要能说出:Linux 对文件权限的判断本质是对 uid、gid 的匹配,而不是对“用户名”字符串的匹配。所以用 usermod -u 改 UID 后,文件属主也会随之变化。
我也建议花时间看一下 /etc/passwd、/etc/group、/etc/shadow 的字段结构。这些文件是用户管理的基础,比单纯背命令更接近本质。
5.3 内核延伸:读拦截、写拦截与透明加密
热词中的 “file_operations 拦截 read/write” 和 “透明加密” 属于 Linux 内核/驱动开发的进阶话题,基础指令阶段不需要深入实现,但可以理解其方向:Linux 把所有外部设备的读写抽象成 file_operations 结构体,里面包含 read、write、open、release 等函数指针。开发内核模块时,通过替换这些函数指针,就可以实现对特定文件的读写拦截,这正是很多透明加密、安全审计软件的底层原理。
如果你对这个方向感兴趣,需要先掌握的基础技能链是:
- 熟练使用
lsmod、dmesg、modprobe管理内核模块 - 会写一个最简单的内核模块,了解
module_init/module_exit - 熟悉
open/read/write的系统调用路径 - 了解
VFS层和inode的基本概念
这套体系不是一两篇教程能覆盖的,如果你从基础指令开始一步步学到内核层,至少要走“用户态命令 -> 系统调用 -> VFS -> 驱动程序”这条路线。作为基础篇,这篇文章先点到为止。
写在最后:我没有讲的指令,你该怎么补
其实 Linux 指令本身不复杂,真正难的是“在什么场景想起用什么指令”。我自己的方法是建一个速查文档,把每条指令对应到“解决什么问题”上,而不是孤立地记参数表。
如果你正处入门阶段,我建议把这篇文章涉及的命令依次在虚拟机里跑一遍,尤其是 useradd、chmod、tar、ps 这几组最核心的。跑通一遍之后,你对“Linux 是一个多用户、有权限意识、能自己管进程的操作系统”这件事就有了真实的体感,而不是停留在“敲命令能出来结果”的层面。
下一篇我计划把网络相关指令(ip、ss、curl、ping、traceroute、dig)系统梳理一遍,再把 systemd 服务管理单独展开,因为这两个方向在真实运维中的出场率实在太高了。如果你有特别想优先看的指令模块,也欢迎在评论里告诉我。
