1. 从任务自动化到故障排查:一套够用的Linux命令实战笔记
如果你接手过一台陌生服务器,或者第一次拿到一个只有终端界面的云主机,多半会产生一个直观感受:手里没几张“牌”,心里不踏实。Linux命令这张牌,不需要你把整本手册背下来,但你需要一套高频率、可组合、能应急的基础集。这篇文章不是一个面面俱到的命令百科,而是从真实使用场景出发,把日志追踪、系统排查、文本处理、网络诊断这类高频动作拆开揉碎,顺便把那些容易踩一脚的坑一并标记出来。
这篇文章适合谁?刚接触Linux的新人、从Windows迁移过来的开发者、以及使用服务器时总在几个命令之间反复横跳的运维新手。解决的痛点是:当系统变慢、服务起不来、日志狂刷、进程卡死时,怎么能用最少的命令组合快速定位问题,而不是依赖网页搜索去临时拼凑。
命令本身是死的,组合方式是活的。整篇文章会按照“信息获取、文本处理、系统状态、网络排查、效率操作、故障速查”这条主线展开,每一条都会讲清楚为什么这样用、在什么场景下最值,以及有哪些隐藏的细节,看完就能在终端里直接上手。
2. 文本处理三件套:grep、awk、sed的高频组合打法
2.1 grep并不只是“搜索”这么简单
很多人对grep的印象停留在“从一个文件里找出包含某个词的行”,但真实的高频用法远不止这个。比如排查日志时,你的第一反应通常不是找某个精确字符串,而是找某个特征模式,比如所有以“2026-06-15”开头的行、所有包含IP地址的行,或者所有状态码不是200的行。
grep -E "2026-06-15|2026-06-16" app.log grep -E "^2026-06-15 10:" app.log grep -v "healthcheck" app.log grep -c "ERROR" app.loggrep -v是反向匹配,用来剔除干扰项。比如.服务总在健康检查的日志里混入大量噪音时,直接反向排除可读性翻倍。grep -c是计数而不是列内容,适合快速判断某个错误是否爆发式增长。再配合-n输出行号、-i忽略大小写,大部分搜索需求都能覆盖。
组合场景更常见。比如你要看某个时间段内,某个用户ID的报错分布:
grep "2026-06-15" app.log | grep "user_1024" | grep "ERROR" | wc -l这里wc -l统计行数,和grep配合可以快速量化问题的严重程度。但要特别提醒一个经典误区:管道串联多个grep时,如果前一个grep匹配范围过宽,后一个grep会把流量放大,导致你在错误的数据集上做判断。建议先把grep条件写紧凑,再考虑组合。
另一个容易被忽略的细节是grep对中文和特殊字符的处理。日志中如果含有中文,或者查询的字符串里混有方括号、星号,不加-F(固定字符串模式)时会被当作正则表达式解析,结果就是查不到或者匹配到莫名其妙的内容。遇到这类情况,直接加grep -F "你要查的原文"就能避开正则干扰。
2.2 awk是终端里的“列处理手术刀”
awk处理日志的价值在于它有天然的“列感知”能力。一个典型的日志行长这样:
2026-06-15 10:23:45 ERROR server 192.168.1.10 connection timeout你会经常希望取出第7列(IP地址),或者按某个字段做聚合统计。此时awk一行就能解决:
awk '{print $1, $2, $NF}' app.log awk '$3=="ERROR" {print $1, $2, $7}' app.log awk -F':' '{print $1}' /etc/passwd第一行打印日期、时间和最后一列($NF表示最后一个字段,NF是字段数变量,这个技巧非常常用)。第二行做条件过滤:只输出第3列为ERROR的行。第三行通过-F指定自定义分隔符为冒号。把分隔符从默认的空格替换成冒号之后,解析/etc/passwd这类配置文件就变得异常高效。
awk在处理“统计排行”这个场景时尤其值钱。比如你想知道日志里出现最多的7个IP地址:
awk '{print $7}' app.log | sort | uniq -c | sort -k1 -nr | head -7这一串组合的含义是:先取出IP列,排个序,然后去重计数,再按计数从大到小排序,最后取出前7条结果。这个命令串在实际工作中几乎每天都会出现,看到uniq -c里的计数、sort -k1 -nr里的数值逆序排序,基本就是统计类场景的标准配方。
有个细节值得注意:uniq去重只能作用于相邻行,所以必须先sort再uniq,否则相同项会被分成多个计数。这个顺序错了,统计结果直接胡来。不去记这个原理也行,只要记住“先排序再去重”这个口诀。
2.3 sed简化批量替换与定向编辑
sed最常见的两个场景,一个是批量替换文件内容,一个是有条件地打印指定范围的行。文件内容替换在配置文件改动场景里价值极高,做过的同学应该知道,在几十个配置节点里手动一个个改有多绝望:
sed -i 's/127.0.0.1/0.0.0.0/g' config.ini sed -n '30,60p' app.log sed -i '/^#/d' config.ini第一行把config.ini里所有127.0.0.1全部替换成0.0.0.0,g表示全局替换。-i是原地修改,不加的话只是把结果输出到屏幕,难免会犯“以为改了但实际没改”的低级错误。当你需要在几台远程机器上同步做这样的改法时,配合一个循环就能批量搞定,但前提是-i这个参数不能漏,而且最好先在一个副本上验证替换结果。
第二行只打印日志第30到60行,调试崩溃信息或者定位特定时段的上下文时特别有用,比head/tail灵活。第三行删除所有以#开头的注释行,清理配置文件时比较顺手。
sed最容易被忽略的是“不带-i时会输出到标准输出,不改变原文件”这一点。很多人第一次用sed替换后发现文件没变,就是没理解默认行为是“读文件、变换、输出”,而不像vim那样直接进入编辑模式。建议所有使用sed -i的场景先做一次无-i的预演,确认替换结果对了再真正落盘。
3. 系统状态和进程排查:从指标到定位再到处理
3.1 top命令的正确打开方式
每次系统卡顿大家的第一反应都是看top,但看什么却容易忽略。有些同学看到CPU使用率100%就急着找进程杀掉,实际上可能要区分两种情况:一是某个进程确实吃满了CPU,二是系统整体负载高但CPU空闲,后者可能涉及的是IO等待或内存换页。
top输出的第一行有load average三个数字,分别代表过去1分钟、5分钟、15分钟的系统平均负载。如果你看到一个数字明显高于CPU核心数,就意味着系统处于过载状态。第二行能看到进程总数和正在运行的进程数,运行中的数量持续超过CPU核心数,说明排队严重。再看第三行和第四行的CPU状态和物理内存状态,借用这些指标可以快速判断瓶颈方向。
按1键可以展开每个CPU核心的使用率,按P键按CPU使用率排序,按M键按内存占用排序,这些交互快捷键比反复退出重进高效得多。建议实际操作时,先在top里按M看看是不是某个进程把内存打满了,再按P看看是不是CPU被某个进程霸占。两个键一按,基本把90%的“不知道谁干的”情况摸清了。
纯命令行场景下还有top -b -n 1非交互模式,把当前状态一次性打印出来,配合head或者管道重定向可以生成系统快照。这个批量采集方式配合cron可以做监控脚本的数据源。
3.2 ps、kill和进程状态识别
ps是补充top的进程明细大杀器。排查问题时尽量使用:
ps -ef ps -aux ps -ef --sort=-%cpu第三条命令按照CPU使用率降序排列进程,看到“罪魁祸首”的进程PID后再决定下一步操作。ps -ef和ps -aux的字段含义略有差异,但判断PID、PPID(父进程ID)、CPU、内存这几个核心指标完全够用。最怕的是只记ps不带参数,输出结果极其简略,丢失了关键字段。
拿到PID后,常见的处理方式就是kill。但kill也有讲究,默认的kill PID其实是发送SIGTERM信号,这个信号给进程一个“体面退出”的机会,进程可以自己清理资源。如果进程已经僵死或者不响应,就需要升级到kill -9,也就是SIGKILL信号,强制终止,不给任何善后的机会。这条命令是最后的底牌,能不用就不用,因为它会让进程来不及保存数据或释放锁,严重时会造成数据损坏。
还有一个高频排查场景:找到“某个服务是否已经启动”。ps -ef | grep nginx加grep过滤是最常见的操作,但很多人会遇到grep自己也匹配到了自己的假象,也就是grep nginx这一行出现在结果里。解决办法是ps -ef | grep nginx | grep -v grep,或者更干净的方式是pgrep -l nginx,直接从进程名匹配。这两个差别在自动化脚本中尤其明显,相同的一个操作,如果用的是裸grep,进程没起来时会混淆判断。
3.3 磁盘、内存和文件占用:看着小实则致命的坑
磁盘写满是一个经典且隐蔽的问题。df -h能快速看到各挂载点的使用率,当使用率到90%以上,建议先看有没有大文件可以清。但删除一个正在被进程占用的大文件时,你会发现磁盘空间没有立即释放——这是因为这个文件虽然被“删除”了,但进程仍然持有这个文件的文件描述符。此时磁盘空间要等进程关闭或重启后才真正释放。
这个坑几乎每年都会在线上环境遇到一次。定位到已删除但还在占空间的文件,可以用:
lsof | grep deleted找到对应的PID之后,要么重启进程,要么通过/proc/PID/fd/下的描述符把文件“找回来”再清空,比如> /proc/1234/fd/18就能直接截断那个文件。这个操作比较复杂,日常更推荐直接重启相关进程,在维护窗口利用lsof确认无占用之后再做清理。
内存检查用free -h就能看个大概。需要提醒的是,Linux系统里大量内存被用作缓存(buff/cache),这部分其实是可被回收的,free的输出里available一列才是真正“可分配”的内存。看到used偏高不用慌,availability才是判断标准。如果available持续走低,再考虑排查进程内存占用。
du -sh是排查具体目录大小的利器。进入一个有问题的应用目录后,逐层du -sh *按磁盘占用大小排序,能快速找出膨胀的日志目录或临时文件目录。有人会问为什么不用ls -lh看文件大小?因为du是看“实际占用磁盘块大小”,对文件和目录都适用,目录这种聚合统计是ls给不了的。
4. 网络排查与端口操作:从延迟定位到连接问题
4.1 ss命令完全替代netstat
ss是netstat的现代替代品,主要原因是输出快、信息全、兼容性好。核心用法:
ss -tlnp ss -tunap ss -s第一条列出所有监听的TCP端口,-p会显示进程PID和名称,排查端口被占用时异常关键。第二条列出所有TCP和UDP的连接状态,-a包含所有状态而非仅监听状态。第三条是汇总统计,显示当前总连接数、TCP各状态的数量,判断是不是出现大量TIME_WAIT时,这条命令几乎一句话说明问题。
排查端口占用时常见的一种困惑是“明明进程还在,但端口连不上”。这种情况通常不是端口没监听,而是ss过滤条件没写对。加个具体端口过滤:
ss -tlnp | grep 8080或者直接用ss -tlnp 'sport = :8080'。前者简单直接,后者更精确,但需要记语法。实战里除非是在自动化脚本中反复使用,否则用grep过滤更顺手。
很多教程还在推netstat -tunlp,并不是不能用,而是ss默认就整合了更多连接信息,且在大并发场景下不会再出现“命令卡半天”的现象。既然现在的发行版都内置了ss,直接用新工具就好。要说学习的成本,几乎为零,参数结构基本一致。
4.2 curl不只是网页调试工具
curl看似是做请求调试的,实际上也能干网络排查的活:
curl -I https://example.com curl -v https://example.com curl -w "dns: %{time_namelookup}s, connect: %{time_connect}s, total: %{time_total}s\n" https://example.com第一条只取响应头,判断站点是否存活。第二条输出整个HTTP请求过程中的详细信息,包括DNS解析、TCP连接、TLS握手、响应头,每一步耗时都能看到。第三条指定输出格式模板,是定位“用户觉得慢但不知道慢在哪”的利器。它能明确把DNS解析时间、TCP建立时间、整体请求时间分开,如果time_namelookup特别长,说明本地DNS解析环节有问题;如果time_connect特别长,那大概率是网络路径或防火墙干扰。
排查接口问题时,curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' url再常见不过。需要注意的是-d参数在curl里默认会使用POST方法,此时-X POST其实可以省略,但显式写明更易读,团队协作时也省去别人猜意图的时间。
诊断证书问题时,curl -k会跳过证书验证,但这只是调试时临时使用,千万不要写进生产环境脚本,那等于主动关掉了TLS的基本安全检查。我曾经见过有人为了绕过本地代理的证书报错,直接把-k写进定时任务里,这是完全不应该发生的事情。
4.3 ping、telnet、nc:连通性的三层诊断法
当服务之间调用失败时,很多人一上来就怀疑代码问题,实际上网络层可能早就断了。这里有个三层连通性排查的习惯:
先ping目标主机,能通说明网络层正常,但要注意服务器通常会禁ping,所以ping不通也不代表断网。下一步用telnet IP 端口探测目标端口是否开放,能握手成功就能确认TCP层的连通性。如果telnet没有安装,可以降级使用nc -vz IP PORT。这个命令总是被忽略,但它恰恰是判断“网络通不通”和“端口通不通”的简单利器。
比nc -vz更高级一点的用法是用nc直接抓取某个端口返回的初始数据:
echo "" | nc -w 3 192.168.1.10 8080这在排查一个HTTP服务是否真的在响应,而负载均衡却始终不分配流量时,会有奇效。它能让你直接看到服务端返回的http响应头或错误信息,不用等上层应用日志。
做连通性排查时建议逐步缩小范围:先在同一台机器上测试localhost,确认服务本身的端口在监听;再从业务调用方所在机器测试目标IP和端口;最后再从外部网络角度测试公网入口。每一次测试都缩小了范围,网络问题、防火墙问题、服务问题就能被快速分离出来。
5. 文件操作、输出重定向与后台任务的高效姿势
5.1 输出重定向的细节:>、>>、2>&1到底什么区别
新手最困惑的一个点是,同样一段日志命令,为什么有的输出能看到,有的一闪而过啥也没有。根源多半出在标准输出和标准错误的区别上。
运行命令时默认有两条输出通道:标准输出(stdout)和标准错误(stderr)。>和>>重定向的只是标准输出,错误信息仍然会直接打到屏幕上。所以你想把错误信息也一起存到日志文件里,必须写:
python run.py >> app.log 2>&12>&1的意思是“把标准错误指向标准输出当前所指向的地方”,此刻就是app.log。这个写法有严格的顺序要求,2>&1必须放在重定向目标的后面,一旦顺序错了,错误信息可能跑到别处。比如2>&1 >> app.log这样的顺序,会让标准错误先指向终端,再让标准输出指向文件,结果错误信息依然留在屏幕上。
只关心错误信息时有更精准的写法:
command 2> error.log这样标准输出继续显示在终端上,错误单独落入文件。排查程序启动失败但又不想看到大量正常日志的场景下,这个命令直接过滤噪音,效果立竿见影。
5.2 管道与xargs:批量操作的标准范式
管道的组合能力让Linux命令变得非常灵活,但管道本身存在一个限制:管道连接的是命令的标准输出到下一个命令的标准输入,并不是所有命令都接受标准输入作为参数。比如rm、cp这类命令,它们接收的是命令行参数而不是标准输入,所以ls | rm这种用法是行不通的。
到这里xargs就该出场了,它将管道传过来的标准输入转换成参数,传给下一条命令。一个经典的高危但高效场景:
find /tmp -name "*.tmp" -type f -mtime +7 | xargs rm -f这条命令会找到/tmp下所有一周前的.tmp文件并删除。但请格外注意:使用xargs时如果觉得不放心,先去掉rm -f,改用xargs ls -l或者xargs -p确认一下要处理的文件列表,再真正执行删除。xargs -p会在执行每条命令前提示确认,虽然步骤多了点,但至少能避免误删。
xargs还有一个有趣的参数-n,它控制每次传递给命令的参数数量。配合curl做批量的HTTP请求时,cat url_list.txt | xargs -n 1 curl -I可以逐条处理,而不是把所有URL一次性塞给curl。
5.3 nohup、&与日志输出:让任务挣脱终端束缚
运行一个类似数据同步脚本的长时间任务时,最怕的是关闭终端导致进程被杀。默认情况下,终端关闭时终端上的进程组会收到挂断信号(SIGHUP),进程就会终止。解决方式是在命令前加nohup,忽略挂断信号,再在命令末尾加&放到后台运行。
nohup python long_task.py > task.log 2>&1 &这个命令组合的意思是:以后台方式运行脚本,忽略终端关闭的影响,标准输出和错误都写入task.log。执行完这条之后会立即回到shell提示符,可以用tail -f task.log或者ps -ef | grep long_task观察任务状态。
这里需要注意一个最常见的坑:nohup ... &之后,进程虽然进入后台,但它仍然是当前shell的一个子进程。如果你执行exit正常退出shell,一般不会有问题;但如果终端被强制关闭,进程可能仍然被终止。真正要避免这个状况,需要配合setsid或者将它托管到systemd之类的服务管理器中。平时做演示或者临时任务用nohup足够,生产环境还是建议用系统服务管理来托管长期任务。
5.4 tail的追踪模式和文件截断的关系
tail -f应该是日志排错中出现频率最高的命令,但用起来也要留意“追踪的是文件描述符还是文件名”。
默认情况下tail -f追踪的是文件描述符,当日志文件被logrotate轮转(名字变了,或者原文件被替换)时,你会发现tail继续在旧文件上追踪,新日志根本没有显示。此时可以用tail -F(大写),它会按时重新打开文件,追踪的是文件名而非文件描述符,日志轮转后依然能继续跟上。
另外在做清理场景时,一个大日志文件有几十GB,如果想要清空它但保留文件占用,可以用cat /dev/null > app.log或者> app.log。这里千万不要用rm app.log然后创建一个新文件,因为之前持有文件描述符的进程仍然在写入已被删除的文件,磁盘空间还是不会释放。这个坑和我前面提到的已删除文件占空间的场景高度关联,本质上都是文件描述符在作怪。
6. 高频故障场景速查:定位、验证、恢复的实战套路
6.1 服务端口起不来?按顺序查这五项
端口起不来常见原因五花八门,但如果按照固定顺序排查,几分钟内一定能定位出问题所在。
第一步查端口是否被占用:ss -tlnp | grep 端口号,有输出就是被占,找到PID,确认是不是旧版本进程残留。第二步查配置文件语法是否正确,比如Nginx可以用nginx -t,很多配置错误在服务启动输出里并不直观,但自带检查命令会给准确提示。第三步查进程状态:ps -ef | grep 服务名,看是否处于僵死状态。第四步直接看启动日志:tail -50 /var/log/xxx.log,多半有报错信息。第五步看磁盘和内存余量:df -h和free -h,资源不足也会导致服务启动时直接被kill。
这五步的顺序可以因人习惯调整,但大致思路是一致的:从占用冲突到配置问题,再到进程状态、应用日志、系统资源,逐层收窄。若五步全部通过但服务依然起不来,那大概率是启动命令发生了变化或权限不够,此时再检查当前运行用户和启动脚本。
6.2 磁盘空间明明删除文件却不释放
这大概是运维新手最容易懵的场景。df -h显示磁盘占用爆满,但du -sh在目录里找一圈,发现所有可见文件加起来也远远达不到占用量。你用ls -lh看文件都已经删掉了,空间却纹丝不动。
这时候第一反应应该是lsof | grep deleted,看看是否有进程仍然持有已删除文件。如果有,记录进程PID,通常解决路径是重启进程或服务。有时候这个进程只是某个日志写入器,重启成本很低,也有的场景是数据库这类大进程占用,需要谨慎处理。这也是前面提过的文件描述符问题的经典表现。
如果不想立时重启,还可以尝试用ls -l /proc/PID/fd | grep deleted找到具体的文件描述符序号,然后执行> /proc/PID/fd/序号来清空内容。这个操作比较底层,适合临时缓解磁盘压力,解决完之后还是要想办法彻底重启进程释放空间。
6.3 CPU飙高但找不到占用者
典型现象是top看到负载很高,但进程列表里没有一个吃CPU的,这时候不妨观察top输出第一行里的wa(IO wait)指标。如果这个值很高,说明系统的大量时间其实在等待磁盘输入输出,而不是CPU在执行指令。这也解释了”负载飚高但CPU使用率不高”的悖论。
此时需要确认具体是哪个进程在产生大量IO,用iotop(需要安装)可以直观看到每进程的IO读写带宽。没有iotop时可以先看dstat或sar这类工具采集IO指标,再定位进程全貌。若是日志写入频繁造成IO压力,就需要考虑切分日志或者优化写入量;若是备份任务在深夜启动导致IO集中,那就需要调整任务执行时间。
由于虚拟化环境对IO指标有干扰,很多云服务器的wa虚高,所以看到高wa也不用着急认定是磁盘故障,先看看有没有大任务在跑、交换分区是否在频繁使用。
6.4 TIME_WAIT过多如果被当成异常处理反而帮倒忙
ss -s显示大量TIME_WAIT连接时,新手会恐慌。实际上TIME_WAIT是TCP协议正常的状态,表示主动关闭连接的一方已经在等待足够的超时时间,确保远端收到最后的ACK。高并发短连接场景必然伴随大量TIME_WAIT,这是系统正常工作状态的信号,不是故障。
唯一需要注意的是,如果TIME_WAIT量极大且占用了大量端口资源,可能会影响新连接的建立。常见解决思路是调整内核参数,比如启用net.ipv4.tcp_tw_reuse(针对客户端发起的连接,不适用于服务器)或调低net.ipv4.tcp_fin_timeout,这些调整需要在理解业务模型后谨慎进行,不是遇到TIME_WAIT就必须改。
所有进程、连接状态、日志输出终归是表象信息。解决问题的核心还是在于能把不同维度的信息串联成一条因果链。命令只是加速这个过程的手段,背后的排查逻辑才是真正要花时间沉淀的部分。
7. 最后的几个实操心得
用几条命令确实能解决大多数问题,但工具再多也会遇到“每个命令都正常,但问题就是复现不了”的诡异局面。这时候我的建议是回过头检查环境差异:命令是在本地主机跑的还是容器里跑的;同一个命令在不同发行版上的行为是否有差异;配置文件里有没有因为换行符而导致解析出错。命令本身没有问题,只是它运行的环境变量、用户权限、启动方式可能跟你默认想的不一样。
如果绝大多数操作都要在一台陌生机器上展开,第一件值得做的事不是盲目敲命令,而是先把机器版本、用户权限、已有服务理清。cat /etc/os-release、whoami、ss -tlnp、systemctl list-units --type=service --state=running各跑一遍,整个环境就清晰了。很多排查困境其实都是因为前置信息不足,而不是命令不会用。
从个人实际经验来看,最能提升效率的不是多背命令,而是把高频场景组合固化。像“端口是否被占用”“当前谁在监听”“日志最新报错是什么”“内存和磁盘状态如何”这类组合模板,只要记熟前几条命令,基本能快速拼出一张系统健康快照。把命令当积木,组合方式才是真正的个人操作系统。