
Linux命令这个东西入门容易精通难。之前把基础篇发出来之后不少人后台留言说ls、cd、grep、ps这些确实会用了但真遇到实际场景还是慌不知道哪条命令该配哪个参数更不知道多条命令怎么串起来用。这篇“Linux命令2”就是冲着这个需求来的聚焦日常干活时真正高频出现的组合技从文件处理、系统排查、网络诊断到效率提升每个场景都给可直接套用的命令组合。适合已经会用基础命令、想进一步提升实操能力的同学也适合刚接手服务器维护、想在排障时少走弯路的朋友。1. 命令是死的人是活的先建立正确的命令学习思路1.1 为什么看教程都会一到操盘就废我见过不少朋友把《鸟哥的Linux私房菜》翻了好几遍命令背得滚瓜烂熟可服务器一报警就懵了。原因很简单教程是按“命令”分类的比如“find命令详解”“grep命令详解”但现实是按“任务”分类的——你要解决的是“找出上周改过的配置文件”“看看谁在疯狂占CPU”“端口为什么起不来”。一个任务往往要用到四五条命令组合中间还夹着管道、重定向、循环教程里很少把这些串起来讲。举个例子。有人想“找到最近2小时改过的所有PHP文件然后挨个看看改了什么”他脑子里第一时间想到的是vim但根本不知道入口在哪。正确的姿势是先用find把文件筛出来再配合管道和编辑器打开。这个流程里find、xargs、vim三个工具缺一不可但单看任何一条命令的教程都学不到这个完整套路。所以我把“Linux命令2”定位成“场景化命令组合课”核心不是多背几十条命令而是建立一种思路以后遇到问题先拆任务再想工具最后组命令。1.2 从“记住命令”到“组装命令”管道思维是关键Linux命令的设计哲学和乐高积木很像。每条命令只干一件事然后把输出交给下一条命令继续处理。这个“把输出交给下一条命令”的机制就是管道符|。我见过很多新手写命令一写就是一大串各种参数堆在一起其实完全可以用管道拆开。比如你想看当前哪个进程吃内存最多最朴素的办法是ps aux | sort -rk4 | head -10这条命令拆开来看就很好理解ps aux把所有进程列出来。sort -rk4按第四列%MEM内存占用百分比做逆序排序内存占用大的排前面。head -10只看前10行屏幕不会刷屏。如果不用管道你得先把ps aux的输出保存到文件再用编辑器打开排序再挪到屏幕最上面多三步操作不说还容易出错。管道让每一步的输出都成为下一步的输入核心是“文件不用落地”。还有一个非常重要的点重定向。是覆盖写入是追加写入2是把错误信息单独写到文件。排错的时候把日志信息分流到不同文件区分正常输出和报错输出能省下大量反复排查的时间。比如find / -name *.conf conf_list.txt 2 error.log正常找到的文件写进conf_list.txt权限不足报错的写进error.log两边互不干扰。这个习惯看起来不起眼真到生产环境排查的时候特别管用。2. 文件操作进阶比mv和cp更值得掌握的组合技2.1 批量改名、批量移动循环和rename让重复操作消失日常维护里最常见的重复劳动就是“批量处理文件”。比如日志归档每天要把前一天生成的app.log改名成app-2025-01-01.log再挪到归档目录。手敲一条条mv命令太蠢我一般这么写for file in *.log; do mv $file app-$(date %F)_$file done这串命令里的细节比看起来丰富得多。*.log是通配符匹配所有以.log结尾的文件。$file必须加双引号不然文件名里一旦带空格mv会把它当成多个参数直接报错。$(date %F)是命令替换执行时会先跑date %F得到类似2025-06-22的日期字符串再拼接到文件名里。双引号在赋值和引用时都要用完整的避免Word Splitting把含特殊字符的文件名拆开。批量重命名文件也可以直接用rename命令。不同发行版自带的rename版本不一样Debian/Ubuntu系列是Perl版本支持正则表达式CentOS/RHEL系列是util-linux版本只支持简单的字符串替换。建议先执行rename -V看版本。Perl版批量把old替换成newrename s/old/new/g *.txt这里的s/old/new/g就是Perl正则替换语法s表示替换g表示全局替换。如果文件里包含目录层级还想递归处理先find再xargs比直接rename更稳find . -type f -name *.tmp | while read f; do mv $f ${f%.tmp}.bak; done${f%.tmp}是Shell参数扩展表示去掉文件名的.tmp后缀再拼上.bak实现“把tmp后缀文件改成bak”。2.2 磁盘告警时5分钟定位大头文件服务器磁盘写满是运维朋友最常遇到的告警之一。这时候别慌按两步走。第一步看整体容量df -hdf -h会列出所有文件系统的挂载点、容量、已用、可用和使用率。-h参数把体积转成人类可读的GB、MB单位不然看到一堆字节数还得心算。输出里找Use%接近100%的挂载点锁定问题盘。第二步往下钻取找大头文件或目录du -h -d 1 /home | sort -hr | head -20du -d 1只汇总当前层级下第一层子目录的大小避免像du -sh *那样把大目录的所有子目录全部算一遍非常慢还会递归到挂载点里去比如遇到/proc这种虚拟目录直接把机器拖垮。排序用sort -hr表示按人类可读格式做逆序排序排序结果比直接sort -n更直观。定位到大目录后继续逐层深入du -h -d 1 /home/xxx | sort -hr | head -10一直钻到最大文件被揪出来为止。这个过程熟练后五分钟内一定能把“谁把磁盘吃满了”找出来。还有一个经常被忽略的问题inode耗尽。磁盘空间没满但创建不了新文件这时候要看df -i。inode是文件系统用来记录文件元信息的数据结构每个文件和目录都要占一个。小文件特别多的场景下inode比空间先耗尽。排查命令df -i /homeUse%达到100%时即使df -h显示还有几GB空闲你也写不进新文件。解决方法一般是删掉大量无用的小文件比如某个程序产生的临时文件、缓存文件。2.3 从“找文件”到“找内容”find、grep、rg怎么选find按文件名、修改时间、文件大小等属性筛选是“找文件”的工具。比如找三天内改过的配置文件find /etc -type f -name *.conf -mtime -3关键是-mtime -3表示最近3天内修改过3表示超过3天没改过。-type f限定只找普通文件不然目录、链接也会混进来。grep是“找内容”的工具它在一堆文件里搜包含特定文本的行。比如在某个项目里搜哪里调用了某个函数grep -rn getUserInfo src/-r递归子目录-n显示行号--include*.java可以限定只在Java文件里搜。实际工作中我更推荐用rgripgrep替代grep -r它默认忽略二进制文件和.git目录也不会陷入隐藏目录搜索速度比grep快一个量级。如果机器上没装一条命令搞定apt install ripgrep # 或者 yum install ripgreplocate是另一个容易被忽略的查找工具它基于预建的数据库查找速度极快locate nginx.conf但locate的数据库不是实时更新的刚创建的文件可能搜不到需要先sudo updatedb刷新索引。这个工具适合找“你知道肯定存在、但忘了具体路径”的文件不适合排障时的实时搜索。3. 系统状态排查进程、端口和服务一次搞清3.1 进程排查从ps到pstree别只盯着top看接手一台陌生服务器我通常先跑一条命令看整体负载ps aux --sort-%cpu | head -15--sort-%cpu表示按CPU使用率降序排序前面带头的是吃CPU最狠的进程。想看内存占用改成--sort-%mem即可。top命令虽然也能看实时状态但它在交互界面里不方便直接跟其他命令组合写脚本、做自动化时ps更顺手。有时候发现问题进程是某个服务派生的子进程靠ps aux的行列关系看不清楚父子关系。用pstree -ap能把进程树画出来一眼看出谁是谁的爹pstree -ap | grep nginx进程排查必然涉及清理进程。kill默认发SIGTERM信号相当于礼貌地请进程自己收尾退出给它机会保存状态、关闭文件、释放资源。kill -9发SIGKILL属于直接打死进程没有机会做任何清理动作。我见过不少朋友一上来就kill -9结果数据库、应用服务数据不一致恢复成本极高。正确选择是普通服务进程排队退出kill pid进程假死、无响应kill -9 pid按进程名批量结束pkill -f 服务名关键字注意-f是全命令行匹配容易误杀其他包含同样关键字的进程先用pgrep -f确认目标再动手。还有一类僵尸进程ps aux里状态列显示Z。僵尸进程实际上是已经结束但还没被父进程回收的“尸体”kill -9杀不掉它因为它的生命已经结束了。要解决得去处理它的父进程让父进程调用wait回收它或者直接重启父进程。3.2 端口和服务排障ss、systemctl、journalctl三件套服务起不来排在首位的排查动作是看端口监听情况ss -lntp-l只看监听端口-n不做DNS解析直接显示数字IP-t查看TCP-p显示占用进程的PID和名称。输出里Local Address那一列如果显示0.0.0.0:80说明在IPv4的80端口监听显示:::80说明IPv6的80端口也在监听。确认某个端口被谁占了ss -lntp | grep 8080如果服务一直起不来可能是端口被上一个进程占着。找到PID后先确认是个什么进程再决定是kill还是调整配置。systemd管理服务时看服务状态、看单位依赖关系用systemctl status 服务名 # 看服务当前状态和最近日志 systemctl list-units --typeservice --staterunning # 列出所有正在运行的服务 systemctl enable 服务名 # 设置开机自启 systemctl disable 服务名 # 取消开机自启systemctl status的输出非常友好Active状态会直接显示active (running)、failed、inactive (dead)。配合systemctl list-unit-files | grep 服务名查看开机自启的是启用还是禁用状态。如果服务已经运行但其内部有错误最直接的办法是翻日志。systemd管着的服务日志统一收在journald里journalctl -u 服务名 -n 100 journalctl -u 服务名 --since 1 hour ago journalctl -u 服务名 -f-n 100只看最近100行--since按时间过滤-f实时跟踪。这些参数组合起来排错效率比打开一整个/var/log文件干瞪眼高得多。3.3 日志轮转和实时跟踪tail能救命排查运行中程序的异常最常用的命令是tail -ftail -f /var/log/nginx/access.log-f会持续跟踪文件新增的内容日志一有新行屏幕立刻打出来。按CtrlC退出跟踪。如果日志刷新太快导致刷屏可以配合grep过滤只看自己关心的关键字tail -f /var/log/nginx/error.log | grep -i timeout日志文件不会无限增长Linux有logrotate机制自动做日志轮转也就是按天或按大小把旧日志改名备份、压缩再让程序写新的日志文件。日志轮转的配置通常在/etc/logrotate.d/目录下。如果重启服务时发现日志还是继续写往旧文件多半是服务进程没重新打开日志句柄需要systemctl restart 服务名或者让进程重载配置。4. 网络排查与下载传输常用命令的实话实说4.1 连通性测试ping通不代表服务通排查网络问题第一条命令多半是pingping -c 4 192.168.1.1-c 4表示发4个包就停不然会一直ping下去。但这里有个常见误区ping通了只说明目标机器在线并且中间的路由允许ICMP包通行。很多服务器出于安全考虑禁用了ICMP响应这时候ping不通不代表服务不可用ping通了也不代表服务端口能连上。真正要确认“某个服务能不能访问”需要直接测TCP端口。ncnetcat是首选nc -vz 192.168.1.10 3306-v输出详细过程-z表示不发送数据只扫描端口是否开放。看到Connected to 192.168.1.10这样的输出说明3306端口通着MySQL服务可以访问。这里要注意nc -vz如果卡住没反应可以加超时参数nc -vz -w 3 192.168.1.10 3306-w 3表示3秒超时。如果是HTTP服务curl -I能更直接地看到响应头curl -I http://127.0.0.1:8080/health返回HTTP/1.1 200 OK说明服务正常返回502、503、504之类就说明后端服务挂了或者网关配置有问题。这一步能帮你快速区分“网络不通”还是“应用内部故障”。4.2 下载和传数据wget和curl别搞混了下载文件我最常用的是wget它的资源占用小支持断点续传参数-c。比如下载一个大安装包中断了重新执行wget -c https://example.com/archive.zip会从上一次断掉的位置继续下载不用重新开始。批量下载文件列表时把URL逐行写进一个文件再执行wget -i download-list.txtcurl和wget定位不太一样。curl是“用各种协议收发数据”的通用工具测试接口、提交表单、带请求头都靠它。下载文件指定输出文件名curl -L -o archive.zip https://example.com/archive.zip-L表示跟随重定向。很多下载链接先返回302跳转不加-L拿到的可能只是一个重定向响应页面而不是真实文件。这个坑我踩过不止一次。测试一个POST接口curl -X POST https://example.com/api/login \ -H Content-Type: application/json \ -d {username:admin,password:123456}-X指定请求方法-H加请求头-d带请求体。调试的时候加-v看完整交互过程能看清请求头发了什么、响应头又回了什么比任何框架的日志都直观。4.3 定时任务和后台执行让命令自己跑起来有一些操作需要周期性执行比如每天凌晨清理临时文件、每周压缩一次日志手工敲不现实用crontab。编辑当前用户的定时任务crontab -ecrontab每行由“分 时 日 月 周 命令”六部分组成。比如每天凌晨2点执行备份脚本0 2 * * * /opt/scripts/backup.sh /var/log/backup.log 21五个时间位依次代表分钟、小时、日期、月份、星期*代表任意值。 /var/log/backup.log 21把标准输出和错误输出都追加到日志文件否则cron会把输出结果通过邮件发送给用户每天收一堆垃圾邮件。这里特别要提醒的是cron执行命令时的PATH环境变量非常精简系统默认路径里可能没有你的自定义命令。一个很常见的坑是脚本里写python3明明能跑但在cron里执行python3: command not found。解决办法有两个脚本里使用绝对路径/usr/bin/python3或者脚本开头显式导出PATH。需要长时间运行的任务比如启动一个测试服务担心SSH断开了进程被带走用nohup配合nohup /path/to/script.sh /tmp/script.log 21 nohup让进程忽略挂断信号把进程放到后台执行。但说实话我现在更推荐tmux或screen这类终端复用工具比nohup更灵活——你可以在tmux里开一个会话跑任务回头重新连上SSH还能继续看到输出不像nohup那样把输出丢到文件里就结束了。创建会话tmux new -s build退出会话按Ctrlb再按d重新进入tmux attach -t build5. 效率提升别名、管道组合和Shell小技巧5.1 高频率操作靠别名续命给高频命令设置别名是成本最低、见效最快的效率提升手段。比如ls -lh几乎每次都要打我直接把它缩成llalias llls -lh alias lals -a alias ..cd ..写进~/.bashrc然后source ~/.bashrc生效。注意一个坑如果.bashrc里有别名定义但新开的SSH会话不生效多半是没有source ~/.bashrc或者当前Shell不是登录Shell配置文件加载的是~/.profile而不是~/.bashrc。确认当前生效情况alias ll会显示ll对应的完整命令如果没显示说明没加载。另一个实用别名场景是高频目录切换alias webcd /var/www/html/project以后输入web回车直接跳转比按完整路径快多了。5.2 管道组合实战两条我经常用的“一行式”场景一找出当前项目下最大的10个文件决定清理谁。find . -type f -printf %s %p\n | sort -nr | head -10find -printf %s %p\n直接让find输出文件大小字节和完整路径替代了xargs ls -lh的一层调用性能好很多。sort -nr按数值逆序排文件最大排前面head -10取前十个。场景二统计Nginx访问日志里状态码分布快速发现有没有大量5xx错误。awk {print $9} /var/log/nginx/access.log | sort | uniq -c | sort -nrawk {print $9}提取第九列Nginx默认日志格式里第九列就是HTTP状态码。然后sort排序让相同状态码归在一起uniq -c统计每类出现的次数再按次数逆序排列。输出类似302 18420 200 15331 404 112 500 8看到大量500就该立刻查后端服务日志了。这两个例子都是在重复“拆分任务→组合命令”的过程。多练几次这种组合处理问题的速度会明显提升。6. 常见故障与排错技巧实录6.1 故障速查表我把工作中遇到的典型问题和排查路径整理成一个速查表遇到类似情况直接照着走。现象推荐排查命令可能原因常用解决动作磁盘空间满但du找不到大文件lsof | grep deleted有进程删除了文件但仍占用句柄空间没释放找到进程PID重启或kill空间立即释放文件系统只读不能写入mount | grep -w /文件系统错误或挂载只读检查dmesg卸载后fsck修复注意umount前确保无进程占用命令提示command not foundecho $PATHPATH环境变量里没有对应目录确认命令是否安装或修改PATH用绝对路径临时执行端口被占用服务起不来ss -lntp | grep 端口上一个进程还活着确认进程后kill或用lsof -i:端口查占用服务active (running)但业务访问失败journalctl -u 服务名 -n 100服务内部逻辑错误看应用日志检查配置文件和依赖文件删除后感觉空间没变化df -hlsof | grep deleted进程仍持有已删除文件的句柄重启持有该文件的进程CPU负载高但不知道谁干的top -b -n1或ps aux --sort-%cpu有异常进程或业务高峰锁定高占用进程进一步确认是否为预期任务定时任务不执行crontab -l/var/log/cron时间格式错误或PATH问题手动执行脚本确认手动可跑再检查cron日志日志文件一直不增长systemctl status 服务名服务已死或日志轮转导致句柄失效重启服务确认写日志路径权限6.2 我踩过的几个坑提前帮你避开第一个坑在for循环里没加引号。我之前批量归档一批带空格的文件名循环里写的是mv $file $file结果带空格的文件被拆成两个参数一条mv命令报错害得我花时间从错误日志里捞文件名。从此以后凡是在命令里引用变量能加双引号的地方绝不省。第二个坑find和xargs配合时文件名里出现空格或换行默认以空白符分隔导致处理出错。解决办法是让find用null字符作为分隔符xargs用null字符作为输入分隔符find . -type f -name *.log -print0 | xargs -0 rm这条命令在文件名包含空格的特殊场景下完全安全。普通情况下可能没问题一到奇葩文件名就翻车所以稳妥起见建议养成-print0和-0的习惯。第三个坑cron环境变量。我之前写了个脚本里面用了docker命令手动执行一切正常cron执行却总是报错。后来发现cron环境里PATH路径没有包含/usr/bin/docker所在的目录。这个坑排查起来很隐蔽因为脚本本身没问题纯粹是环境问题。解决办法脚本开头加一行export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH。第四个坑kill -9用得顺手结果误伤了正在写缓存数据的服务。当时我图省事直接把一个批量任务进程kill -9导致它处理的临时文件没写完整后续脚本读到残片数据报出一堆诡异错误。现在的习惯是能kill就不加-9先给进程一个体面退出的机会实在没反应再上大招。第五个坑费了好大劲排查日志才发现自己看的是旧文件。有些服务日志是软链接指向当前日期文件的比如/var/log/nginx/access.log - access.log-20250622一旦服务日志轮转原来的日志文件名可能就指向了别的文件。排查前先ls -l /var/log/nginx/access.log看是不是软链接能省很多时间。最后分享一个我个人养成的习惯每遇到一类排错场景就把它记进一个Markdown速查文件附上当时实际跑过的命令和踩坑原因。这种笔记不用很规整自己看得懂就行。命令这东西真正要死记硬背的其实永远就那么几十条更多是靠“场景触发记忆”——问题见得多了命令组合自然就熟。这篇“Linux命令2”算是我自己笔记的公开版希望能帮你在实操时少翻几次车。你如果手头也有什么想补充的命令组合或者踩坑经历欢迎在这篇下面接着聊。