我一直觉得,搞Linux这件事最值钱的不是背了多少命令,而是你有没有一份属于自己的Linux笔记。我这份笔记从第一次在虚拟机里装系统开始记,一路更新到现在,里面既有基础命令的速查,也有线上故障的排查记录,还有一堆“当时觉得简单、事后却坑了好久”的经验。这篇文章就把这套笔记里的核心内容整理出来,适合正在学Linux的新人,也适合想把自己知识体系重新梳理一遍的从业者。我不打算写那种“全网命令大全”,而是想把“怎么记、怎么用、怎么避坑”这条线讲清楚,让你看完也能整理出自己的版本。
1. 这份Linux笔记的体系是怎么搭起来的
1.1 为什么非要有自己的笔记
很多初学者喜欢收藏网上的“Linux命令速查表”“常用命令大全”,收藏了十几篇,真到用的时候还是一个个去搜。原因很简单:孤立地抄写命令,你记住的只是字符,不是场景。真正能被记住的知识,一定附着在某个具体问题上。我笔记里有一条特别典型的记录:某次生产环境磁盘告警,我用du -sh *逐个目录排查,才发现是日志文件占了40多G。这条笔记我不仅写了du -sh *这个命令,还写了当时的排查场景、为什么这命令能快速定位、之后又怎么用find /data/logs -type f -size +500M找出具体的大文件。三个月后我再遇到类似问题,根本不用搜索就能想起完整思路,因为笔记里存的是“问题+方法+原理”的组合,而不是孤零零的命令。
这种“场景化记录”就是我个人笔记体系的第一原则:永远记录你遇到问题的上下文,而不是记录零散的知识点。举个例子,如果你只写“crontab -e 编辑定时任务”,这条笔记几乎是无效的;如果你写“某次脚本每天凌晨不执行,排查发现是cron环境变量没有加载,脚本里用绝对路径解决”,这条笔记才值钱。你的笔记应该像一本错题本,而不是字典。
1.2 笔记分类:别把笔记写成垃圾桶
我见过很多人的笔记,打开就是一个几百行的文本文件,标题叫“Linux笔记”,内容从ls命令聊到内核参数再聊到Docker,什么东西都往里堆。这种笔记最大的问题是:记了等于没记,你根本不会回看,因为每次找东西都得从头翻。
我的做法是分成五大类,用数字编号作为文件名前缀:
| 分类 | 编号前缀 | 内容范围 |
|---|---|---|
| 基础命令 | 01- | 文件操作、文本处理、权限、用户管理 |
| 系统管理 | 02- | 性能排查、日志分析、服务管理、磁盘网络 |
| Shell脚本 | 03- | 自动化脚本、定时任务、脚本调试 |
| 故障记录 | 04- | 每次线上事故的排查全过程 |
| 工具配置 | 05- | 编辑器、版本管理、远程登录等工具备忘 |
在每一类下面,我还会按日期继续拆分,比如04-2024-磁盘写满排查.md。这种方式最直接的收益是:想找一个知识点,基本30秒内能定位到对应文件。这里要加一个个人体会:分类不要太细,五到八类是最高效的区间。分太细你会懒得归档,分太粗和没分一样。这个度,用过几周自然能感觉到。
2. 基础命令笔记:理解底层逻辑才记得牢
2.1 文件和目录操作:别只会ls和cd
基础命令里最容易被低估的是ls和rm。先说说ls。很多人知道ls -l可以看文件列表,但不知道ls -ld和ls -l的区别。我踩过这个坑:有次执行ls -l /etc/nginx/,看到一堆文件时间戳,还以为看到了目录本身的信息,实际上那只是目录内容;想看目录自己的权限和属主,必须加-d,也就是ls -ld /etc/nginx/。这在排查“为什么这个目录我进不去”的时候特别有用。
再说rm。这是Linux里最容易出事的一条命令。我给自己定了一条死规矩:rm前面永远先ls确认。删除目录前用ls -ld看看路径是不是真的对,要删文件就用ls -lh看看文件大小和名字。很多人在生产环境敲过rm -rf /var/log/nginx/,结果多个空格变成rm -rf /var/log/nginx/少个字符,或者路径少写一个字母,就直接把整个目录删了。为了避免这种事故,我一开始就把rm做了alias,默认是rm -i,每次删除都会询问确认;后来熟练了,又把alias改成rm -I,只在批量删除超过三个文件时询问,既保留效率又不至于误删。
关于链接文件,我用一个类比来理解硬链接和软链接:软链接就像Windows桌面上的“快捷方式”,是指向另一个文件路径的指针;硬链接更像是同一个文件起了两个名字,底层指向的是同一个存储区域。有个经典考题:软链接指向的文件被删除,软链接就断了;硬链接即使“原文件名”被删,内容还在,因为另一个硬链接仍然指向数据块。实际运维中,我们用软链接的场景远多于硬链接,比如ln -s /data/www /var/www,把一个大目录的访问路径引到系统预期的位置。我个人建议,新手先掌握软链接就够用,硬链接理解概念即可。
2.2 文本三剑客:grep、awk、sed的实战姿势
Linux下的文本处理绕不开grep、awk、sed这三条命令。我见过不少人把这三条命令当成三个孤立工具记,其实它们解决的是三类不同问题:grep负责“找行”,sed负责“改内容”,awk负责“切列和统计”。当你明确自己要做的是哪类事,就知道该选用哪个工具了。
先说grep,最常见的坑是忘写引号。比如你想查日志里包含2024-06-11 10:00:00的行,如果直接执行grep 2024-06-11 10:00:00 app.log,shell会把空格后的内容当成另一个参数,命令直接报错或者查出来的结果完全不匹配。正确写法是grep "2024-06-11 10:00:00" app.log。带正则时更要注意,比如查以error结尾的行,写成grep "error$",$被双引号保护后grep才能正确识别。
再讲awk的实际用法。找日志里的IP访问量是最高频的场景。假设access.log的每一行第一个字段是客户端IP,要统计访问次数最多的前10个IP,命令是这样的:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -n 10这条命令的每一步我都拆解过:awk '{print $1}'取出每行第一个字段,也就是IP;sort把IP排序,让相同IP相邻;uniq -c统计每个IP出现的次数,并在前面加上计数值;sort -rn按计数值从大到小排列;head -n 10取前10行。这套管道组合几乎能解决所有“日志里谁最多”的问题,不只是IP,换成状态码、接口路径都可以。
sed最实用的是批量替换和按行号取内容。比如把配置文件里所有8080改成9090,直接用:
sed -i 's/8080/9090/g' config.properties这里必须强调-i参数的含义:它是直接修改原文件,而不是输出到终端。很多新手第一次用sed -i,执行完发现文件内容变了,以为保存成功了,其实已经改完了。反过来,有些老手会刻意先不加-i,把替换后的结果打印出来看一遍确认无误,再加-i真正落盘。我自己常年都是这个习惯,尤其是修改核心配置文件之前。另外,sed的正则分隔符不一定是/,当内容本身就包含/时,你可以换用#或者@,比如替换路径/data/a为/data/b:
sed -i 's#/data/a#/data/b#g' config.properties这个小技巧能让你少踩很多转义坑。
2.3 权限体系:chmod、chown背后的设计逻辑
权限这块我用了很久才真正想透。Linux权限设计成三组,每组三个位,分别针对属主、属组、其他人。每个文件的权限位是rwx,有该权限就写1,没有就写0,把三组九个位分别转成二进制,就成了三个数字。这就是为什么chmod 754这样的数字能被人记住:7是rwx,5是r-x,4是r--。你敲chmod 755 script.sh,含义就是属主可读可写可执行,属组和其他人只读只执行,常见于给脚本加可执行权限。
目录权限和文件权限要区别对待,这是最容易被忽略的点。文件只要有r就能读内容,有w就能改内容,有x就能执行;但目录的权限含义完全不同:目录有r才能列出文件名,有w才能在里面创建删除文件,有x才能进入目录。换句话说,如果你对一个目录只有r没有x,你能看到文件名,但cd进去会提示权限不允许。很多“我能看到文件但打不开”的诡异问题,其实都是目录缺了x权限导致的。
关于权限事故,我见过最典型的一起是某人想给网站目录开权限,直接执行了chmod -R 777 /var/www。虽然业务立刻正常了,但风险极大,777意味着任何本地用户都能改写网站文件,一旦有人上传了恶意脚本,后果不堪设想。正确做法是给目录开755、文件开644,需要写权限的特定目录(比如上传目录)单独开775或者用setgid方式管理。我自己的原则是:永远不要用777,这条要写进笔记的第一页。
chown也不复杂,但要注意用户名和用户组可以一起改。比如chown www:www /data/www -R,表示把/data/www的属主和属组都改成www用户,-R递归应用到目录下所有子目录和文件。实际中,很多权限问题的根源不是权限位不对,而是属主不对。比如服务用www用户运行,但文件属主是root,即使权限是755,www用户也可能写不了,这时候chown就是正确的解法。
3. 系统管理与日常运维笔记
3.1 看一台机器到底行不行:CPU、内存、磁盘、网络排查
系统管理这块,我的笔记核心是“四件套”:CPU、内存、磁盘、网络。这套排查思路我用到今天,任何一个“机器变慢”的问题,都会按这个顺序走一遍。
先看CPU。很多新手以为top里显示的CPU使用率99%就是不正常,其实要看的是平均负载load average。这个值有三个数字,分别是1分钟、5分钟、15分钟的平均负载。要注意:它不是CPU使用率,而是“正在运行和等待运行的进程数量”。我打个比方,就像餐厅的排队人数:1分钟排队有10人,5分钟前排队有20人,15分钟前排队有50人,说明客流在明显下降,系统在变好。如果数字持续大于CPU核数,说明有进程在抢CPU。比如4核机器load average长期8左右,基本可以断定CPU资源吃紧,再用top按CPU排序找到最消耗的那个进程,配合ps -ef确认是什么程序。
内存看free -h,这里最容易误读的是buff/cache。我第一次看free时以为buff/cache占了好几G就是内存泄漏,后来才明白这部分是系统用来做缓存和缓冲的,是可以回收的。真正该关心的是available这一列,它才代表“在不发生大量换页的情况下,还能分配给新进程的内存”。如果你发现available越来越小,swap使用率持续增长,那才是真的内存压力。
磁盘这块,我通常会两条命令一起用:df -h看整体分区剩余量,du -sh看某个目录占用多大。df告诉你是哪个分区满了,du告诉你这个分区里什么东西最占空间。举例来说,df -h显示/分区已经100%,接下来就在根目录逐层跑du -sh *,直到找到那个膨胀的目录。这个过程不依赖任何高级工具,但需要一点耐心。
网络排查现在我会后端用ss -tunlp列出正在监听的端口和对应进程,前端用ping和curl -I测试连通性。有一次服务一直报连接超时,我先ping发现网络通,再curl发现端口无响应,最后ss -tunlp一看,进程根本没在监听端口。这就是排查顺序的意义:不是乱猜,而是按“网络层是不是通、端口是不是在听、进程是不是活着”的逻辑逐层排除。
3.2 日志不是摆设:故障排查的正确顺序
日志是我Linux笔记里占比最大的一块,因为90%的故障最终都要靠日志来还原现场。刚开始学Linux时,我觉得日志文件就是占磁盘空间的垃圾,后来被一个线上问题教育了:某服务突然返回500错误,代码层面看了半天没看出问题,最后在/var/log/nginx/error.log里发现“Too many open files”,才意识到是文件描述符被耗尽了。从那以后,日志就成了我排查问题的第一站,而不是最后才想起来。
当前主流发行版把日志统一收进了systemd的journal,也可以用journalctl查看。我的速查记忆是:journalctl -u 服务名看某个服务的历史日志,journalctl -u 服务名 -f实时跟踪,journalctl --since "1 hour ago"只看最近一小时的。如果服务的日志走得是传统文件方式,就看/var/log/目录下的对应文件,比如/var/log/messages是系统通用日志,/var/log/nginx/access.log是Nginx访问日志。
日志级别也很重要。粗看一遍如果只看到ERROR和WARN就能快速筛选;如果什么都没有,再考虑是不是日志级别被调高了。有一次我排查一个诡异的问题:服务起不来,但systemd的日志里没有任何报错,最后发现是程序自己把日志写到了自定义文件,根本没走systemd。这个经验让我学会了一件事:排查日志之前,先确认日志去哪了,别对着错误的日志文件看半天。
3.3 systemd与计划任务:让机器自己干活
现在的Linux系统基本都被systemd接管了,它既管开机启动,也管服务运行状态。我整理systemd笔记时就抓三个核心命令:systemctl status 服务名看状态,systemctl start/stop/restart 服务名控制启停,systemctl enable 服务名设置开机自启。这组命令足够覆盖绝大多数日常操作。
有段时间我负责维护一个内部工具,老是手动启动、一重启机器又要手动拉起来,后来我干脆写了一个service文件放进/etc/systemd/system/。一个最小可用的unit长这样:
[Unit] Description=My Custom Service After=network.target [Service] ExecStart=/usr/local/bin/my-service Restart=always User=nobody [Install] WantedBy=multi-user.target写完用systemctl daemon-reload重载配置,然后systemctl enable my-service设置开机自启,systemctl start my-service启动。之后机器重启,服务会自动起来,进程挂了也会被自动拉起来,这就是Restart=always的作用。
定时任务方面,cron仍然是必备技能。crontab -e编辑当前用户的定时任务,格式是“分 时 日 月 周 + 命令”。比如每天凌晨3点执行备份脚本,写作0 3 * * * /usr/local/bin/backup.sh。这里有一个我踩过的特别深的坑:cron执行脚本时,环境变量和我们手动登录终端时不一样,脚本里如果用了相对路径,或者依赖了某个PATH目录下的命令,就可能直接失败。解决方法是脚本里尽量用绝对路径,或者脚本第一行写上#!/bin/bash并在脚本里显式加载环境。还有,cron命令里的%需要转义成\%,因为%在cron里是换行符的特殊含义。我遇到过定时任务里写date +"%Y-%m-%d"导致任务不执行,最后查文档才发现要写成date +"\%Y-\%m-\%d"。这种细节,不亲自踩一次真的记不住。
4. Shell脚本实战笔记:把重复劳动交给机器
4.1 写脚本之前先想清楚的事
我写Shell脚本最大的体会是:脚本不是写给机器看的,而是写给你自己三周后看的。如果三周后你打开脚本看不懂它在干什么,那这个脚本的质量就要打问号。因此我给自己定了几条硬规矩。脚本第一行固定写#!/bin/bash,明确用Bash解释器而不是让系统瞎猜;每个脚本开头写一段注释,说明这个脚本是干什么的、在什么时候用、有没有副作用;关键步骤要echo出来,让执行者知道当前跑到哪一步了。这些看起来不起眼,但在脚本出问题时会省下大量时间。
变量和引号是新手最容易翻车的地方。Shell里变量赋值等号两边不能有空格,写成name = "test"会直接报错,必须写成name="test"。引用变量时,我基本都习惯加双引号,比如cp "$src" "$dst",因为如果不加引号,你复制一个带空格的文件名时,命令会被拆成多个参数,直接破坏操作。这个坑我踩过不止一次。
写脚本时建议打开两个安全开关。set -e表示脚本里任何一条命令执行失败就立刻退出,set -u表示使用某个未定义的变量时报错而不是当成空值。这两条组合起来,能避免很多“脚本继续往下跑,但已经把错误数据传下去”的连锁问题。还有一个相对进阶的set -o pipefail,把管道命令中任意一环的失败也当成整体失败,比如在管道里执行grep没匹配到内容,默认情况下管道整体还是返回成功,加上这个选项才能正确捕获失败。我自己的脚本标准模板第一行就是:
#!/bin/bash set -euo pipefail这一行写完,脚本的健壮性直接提升一个档次。
4.2 实战:一个环境初始化脚本拆解
我经常要给新服务器做初始化,装软件包、改时区、建目录、配系统参数。刚开始是手动一条条敲,后来整理成一键脚本,现在这个脚本已经成了我笔记里的“镇店之宝”。这里给你一个简化版,你可以直接拿去改:
#!/bin/bash set -euo pipefail # 初始化系统基础环境 echo "=== 开始初始化 ===" # 安装常用软件包 echo "--- 安装软件包 ---" yum install -y vim wget curl net-tools lsof tree > /dev/null # 同步系统时间 echo "--- 同步时间 ---" timedatectl set-timezone Asia/Shanghai systemctl enable --now chronyd # 创建基础目录 echo "--- 创建目录 ---" mkdir -p /data/logs /data/backup /data/apps # 优化文件描述符限制 echo "--- 设置文件描述符 ---" cat >> /etc/security/limits.conf <<EOF * soft nofile 65535 * hard nofile 65535 EOF echo "=== 初始化完成 ==="解释几个关键点。第一,set -euo pipefail在前面已经说过了,这是脚本的第一道保险。第二,yum install -y里的-y表示跳过确认,批量安装时必不可少,但注意这里的包列表是按常用系统的包管理器写的,如果你用别的发行版,要把yum换成对应的包管理器。第三,echo输出每一阶段的提示,让你在脚本卡住时能定位到是哪个环节的问题。第四,cat >> file <<EOF这个写法叫here-document,它可以把多行内容追加写入文件,适合用来往配置文件里批量写入内容。我见过很多新手用echo "xxx" >> file一行行追加,遇到多行配置就痛苦,here-document是更好的选择。
实际执行时有一个特别值得注意的现象:脚本里执行systemctl enable --now chronyd时,如果系统之前没有安装这个服务,命令会报错并因为set -e让整个脚本中断。这是好事,因为脚本在第一时间通知你环境不满足条件,而不是默默继续执行后面步骤,最后整个环境面目全非。
4.3 脚本调试三板斧
脚本出了问题怎么调试?我的三板斧顺序是:bash -x查看执行过程、shellcheck静态检查、echo分段标记。
bash -x script.sh是最直接的调试方式,它会把每一行命令执行前的实际内容打印出来,连变量展开后的结果都看得到。比如脚本里有if [ "$name" = "test" ],你用bash -x跑一遍,一眼就能看出$name实际被展开成了什么,是不是多了个空格,或者是不是没加引号导致语法错误。这个手段能解决80%的脚本问题。
shellcheck是一个静态分析工具,类似代码界的“拼写检查”。它会指出脚本里未定义变量、缺少引号、[和[ [ 用法不标准等一系列隐患。我在本地写完脚本后都会跑一次shellcheck`,把它提示的错误修完再上服务器执行,基本能过滤掉大部分低级问题。
最后是echo分段标记。这个看起来土,但对付那种“脚本跑得很慢,不知道卡在哪一步”的情况特别有效。在每一步关键操作前后各加一行echo,一个“开始执行什么”一个“执行完成”,跑一遍就知道卡在哪个位置。有些人觉得用set -x就够了,但set -x输出太啰嗦,在生产排查时反而不如几个精心放置的echo清晰。
5. 我用什么工具来维护这份Linux笔记
5.1 为什么选Markdown加Git而不是某个笔记软件
笔记工具的选择很重要,因为如果工具不好用,你就懒得记;不记,再好的方法论都是空谈。我这些年试过不少笔记软件,最后稳定在“Markdown文件加Git管理”这个组合上。一句话解释原因:笔记首先是纯文本,纯文本意味着永远可读、可搜、可迁移,不担心某个软件倒闭或格式变味。
我本地的笔记目录结构大概是:
linux-notes/ ├── 01-基础命令.md ├── 02-系统管理.md ├── 03-Shell脚本.md ├── 04-故障记录/ │ ├── 2024-磁盘写满.md │ └── 2024-连接数爆满.md └── 05-工具配置.md所有文件都是Markdown,普通文本编辑器就能打开。搜索也方便,在目录里运行grep -rn "关键词" .就能全局搜索所有笔记内容,比在任何笔记软件里搜索都快。
Git的价值在于版本回溯。我会在笔记有较大修改时提交一次,比如git add .、git commit -m "增加磁盘故障记录"。这样哪怕某天我把一份笔记改坏了,还能用git log找回之前的版本。我还会把笔记目录推到一个远程仓库,用来在多台设备间同步,手机、笔记本、服务器上都能随时查看。这整个方案免费、可靠、不依赖特定平台,用了三年多没出过任何问题。
5.2 笔记维护节奏:怎么让笔记活起来
很多人记笔记是三天打鱼两天晒网,开完头就再也没更新过。我的经验是给笔记设定一个“最低维护频率”,让记录成为习惯而不是任务。我的节奏分三层:
第一层是即时记录。工作中遇到任何问题,解决后立刻打开笔记写几行,哪怕只有一句话也要记。我要求自己超过十分钟的排查,就必须留一条记录,否则刚才怎么解决的,过两周肯定忘。第二层是每周复盘。周六花十几分钟翻一遍这周的新记录,把不准确的地方修一修,把过时的内容标记出来。第三层是每月整理。把一些零散句子合并成有条理的章节,比如同类的排查记录多了,就可以汇总成一张速查表。这个节奏听起来不复杂,真正坚持下来,笔记就会从“流水账”变成一套可以反复查阅的知识库。
我在笔记里还专门保留了一个“未解决清单”分区,记录那些排查到一半、暂时没有结论的问题。这个清单是我维护笔记的最大动力,因为每次打开都能看到自己还有哪些坑没填完,顺手就接着研究,而不是全凭心血来潮。
6. 我踩过的坑和排查心法
6.1 三类典型事故的排查实录
第一类是“磁盘写满”事故。某天监控突然告警,某台服务器的根分区使用率到了100%,然后一堆服务开始报错。我登上去先执行df -h确认哪个分区满了,再执行du -sh /* 2>/dev/null从根目录逐层往下找,最后定位到一个应用日志目录。那个日志文件单日已经写了20多G,原因是某个服务开启了全量调试日志。处理方法是把日志级别改回去、清理当前大文件、给日志目录配置了滚动切割。整套下来问题解决,我也把全过程写进了“故障记录”,重点是提醒自己:日志切割要在服务上线时就配好,而不是等磁盘满了才想。
第二类是“权限爆炸”事故。某位同事在修改网站上传目录时,直接执行了chmod -R 777 /data/www。当天一切正常,第二周网站被上传了一个别的文件,站点目录属性全乱了。排查的时候我看到/data/www下很多文件权限都是777,就知道出事原因了。修复方式是先把所有文件恢复到644、目录恢复到755,再调整属主属组,最后把上传目录单独授权。这里的核心教训是:任何递归修改权限的命令都要慎之又慎,-R只能用在明确的范围里。
第三类是“定时任务失效”事故。某天用户说每天早上生成的报表没生成。排查步骤是:先crontab -l看任务在不在,发现任务还在;然后手动执行脚本本身,能正常运行;怀疑是cron运行时环境的问题,就在脚本里加了一行输出重定向,把执行日志写到文件里,第二天一看,原来脚本第一条命令就报错,因为脚本里用了相对路径,cron的工作目录和手动执行的完全不一样。最后改成绝对路径,问题解决。这条记录后来也让我养成了一个习惯:所有脚本,不管多简单,一律用绝对路径引用文件,绝不在脚本里cd到某个相对位置。
6.2 避坑清单与个人经验总结
从这些事故里我提取了几条人人都用得上的避坑经验,也成了我笔记里最常被翻的一页:
- 删除文件前先用
ls确认,能帮你挡住80%的误删事故。 - 递归修改权限或属主前,先想一想影响范围,
chmod -R一旦落错路径就是批量事故。 - 排查问题的顺序要固定:先看资源(CPU、内存、磁盘、网络),再看进程,最后看日志,不要上来就乱试命令。
- 修改任何配置文件之前,先复制一份备份,比如
cp nginx.conf nginx.conf.bak,改坏了马上能恢复。 - cron脚本内部所有路径写绝对路径,环境变量不要依赖登录shell。
- 脚本里能用
set -euo pipefail就绝不用裸奔模式。
我自己在实际操作中的体会是,Linux的知识点再多,最终能被你记住并熟练运用的,一定是你亲手记过、遇过、踩过的那部分。所以我的建议很简单:从今天开始,打开一个空白的Markdown文件,遇到第一个问题就用“场景+命令+原因”的格式记下来。三个月后你回头看,那份笔记会比任何网上下载的速查表都值钱。
最后再分享一个小技巧:我现在记笔记越来越不爱写完整长段,反而喜欢用几个关键词加上注释。比如记一条:“某日磁盘告警,df -h确认分区,du -sh *逐级定位,find /data -type f -size +500M找大文件。日志记得配切割。”这种写法记录速度极快,回忆时又足够唤起当时的完整思路。你也不妨试试,把笔记变成“给未来自己看的暗号”,等你积累到一百条的时候,它就是你的个人Linux黑皮书了。