首页 / 资讯中心 / 文章详情

Linux运维实用手册:从磁盘排查到日志分析的高频命令实战

Linux运维实用手册:从磁盘排查到日志分析的高频命令实战 ★ FEATURED ARTICLE
前两篇把Linux的基础命令和文件系统梳理了一遍cd、ls、cp、mv、rm、vi、管道、重定向……这些命令单独看都不难但真正到了干活的时候光会这些远远不够。这一篇我打算换个角度不再按命令清单往下背而是把日常工作中真正高频出现的场景拆开聊聊Linux的实用操作磁盘快满了怎么定位大文件、几百万行日志怎么快速过滤、端口被占用时如何找出元凶、定时任务为什么手动执行正常、cron里却没反应。这篇笔记适合刚开始熟悉Linux、或者已经会用基础命令但总感觉效率上不去的朋友。我会尽量把“为什么这样做”也说清楚而不只是丢一串命令。命令本身记不住没关系思路在命令随时可以查真正值钱的是排查问题和处理故障时的判断方式。文章里所有命令我都实际跑过涉及踩坑的地方也会特别标出来大家照着操作基本能复现。1. 文件与目录操作先把高频命令用明白1.1 天天在用的ls、cp、mv、rm其实还有不少细节前面我们已经用过很多最基本的文件命令这里不再重复ls -l、cp -r这类基础用法而是说几个我在实际操作里发现特别有用的细节。第一个是ls的三个常用参数组合ls -lh以人类可读方式显示文件大小ls -lt按修改时间从新到旧排序ls -lS按文件大小从大到小排序。ls -lt在排查“刚刚改了哪个文件”的时候非常顺手比如你怀疑某个配置文件被改过直接ls -lt看目录最近的修改时间一目了然再配合stat看精确时间点基本就能判断是不是刚才那次操作动了它。如果你管理着一台机器上跑的多个服务这几个参数的组合几乎每天都会用到。ls -lh # 人类可读大小4.2K、1.5M ls -lt # 按修改时间排序 ls -lS # 按文件大小排序cp方面我想强调两个不那么常用但很关键的参数cp -a和cp -u。cp -a在复制时完整保留权限、属主、时间戳做配置备份、目录迁移时非常关键。普通cp会刷新目标文件的时间戳、变更属主等你把环境从一台机器迁到另一台可能因为文件属主不对服务启动直接报权限错误。所以备份习惯养成用cp -a能少踩很多坑。cp -u则适合日常增量拷贝比如把本地改过的几个文件同步到服务器某个目录不用纠结哪些文件动过。cp -a src dest # 完整保留权限、属主、时间戳 cp -u src dest # 只有源比目标新时才复制mv有一个容易被忽视的底层差异跨文件系统移动时它并不是单纯的“改名”而是先复制到目标分区再删除原文件。如果 /home 和 /data 在同一个分区mv只是修改目录项速度很快一旦跨分区你会明显感觉到卡顿超大文件相当于被复制了一份复制期间原文件的inode也会变化。所以同步大目录时我通常直接换rsync比mv跨盘更可控、还能断点续传。至于rmLinux没有回收站这层兜底rm -rf一旦执行就真的没了。我平时删除重要目录前会先用find把匹配到的文件列出来确认再删除这个习惯帮我避免过至少两次误删。mv /home/user/bigfile /data/bigfile # 跨分区时实际是复制删除 rm -rf /data/old_dir # 没有回收站执行前必须确认1.2 先find定位大文件再du揪出磁盘大户磁盘写满大概是Linux日常运维里最经典的问题之一。遇到这种场景重点不是只看df -h而是要快速定位哪个目录占得最多、哪个文件异常变大。先看整体概况df -h看块使用率df -i看inode使用率。两者必须结合看有时候df -h显示还有50G但服务却报“No space left on device”那就是inode满了小文件太多导致索引被耗尽。只习惯看df -h的人很容易漏掉这个坑。df -h # 磁盘空间 df -i # inode使用率定位大文件我常用findfind / -xdev -type f -size 100M -exec ls -lh {} \;参数含义拆开解释-xdev表示不要跨过挂载点避免把 /proc、/sys 这些虚拟文件系统也翻进去-type f限定只找普通文件-size 100M表示大于100M-exec ls -lh {} \;是在每个匹配文件上执行ls分号要转义。如果想只看最大的几个文件就改成find /data -xdev -type f -printf %s %p\n | sort -rn | head -20%p是路径%s是字节大小排完序一眼能看到大头。find /data -xdev -type f -printf %s %p\n | sort -rn | head -20如果是目录级别要看整体占用用du -h --max-depth1 /var | sort -rh | head -20。这里du和find分工不同find针对单个文件du统计目录累计占用。排查磁盘时我通常先用du从根或者嫌疑目录逐层往下定位大头再用find把里面超过某个体积的文件列出来。两步配合十分钟内基本能锁定问题。顺便补充一个清理日志的场景如果日志目录里堆积了大量7天没动过的.log文件先用find /var/log/myapp -name *.log -mtime 7 -exec ls -l {} \;预览确认无误后再把exec替换成-delete执行。能预览能删除这是最稳妥的清理方式。提示find的 -delete 选项会在没有权限时静默跳过部分文件所以删除完最好再用find复查一遍。另外永远不要在不确定路径的情况下直接写find / -delete那等于格式化现场。2. 文本处理三件套grep、sed、awk一次讲透2.1 grep的常用参数以及那个容易坑脚本的退出码日志排查是Linux使用频率最高的场景之一而grep就是日志场景里最基础的工具。我日常用得比较多的有五个组合grep -E ERROR|WARN同时匹配多个关键词grep -i timeout忽略大小写grep -C 5 OutOfMemory显示匹配行前后5行上下文grep -v ^$去掉空行grep -rl Timeout /var/log/递归查找并只输出文件名。-E是扩展正则|表示或比先grep一次再grep一次舒服得多。-C在排查异常时几乎是刚需单看一行ERROR往往看不出原因前后几行上下文才是真正的线索。grep -E ERROR|WARN app.log grep -i timeout app.log grep -C 5 OutOfMemory app.log grep -v ^$ /etc/nginx/nginx.conf grep -rl Timeout /var/log/grep还有一个容易被忽视但很关键的行为退出码。grep找到匹配时返回0找不到返回1出错返回2。这个特性在脚本里尤其容易坑人如果脚本开了set -egrep又作为单独命令执行且没匹配到内容脚本会直接退出后面“备份失败”的分支根本走不到。我一开始没注意这个结果某次备份检查脚本莫名其妙中断排查半天发现就是grep退出码的问题。要避免这个情况要么把grep放在if/while条件里要么在不需要中断脚本的地方加上|| true。set -e if grep -q SUCCESS /var/log/backup.log; then echo 备份成功 else echo 备份失败 fi2.2 sed与awk的组合让日志开口说话grep负责“过滤行”sed负责“按行编辑”awk擅长“按列统计”。三者配合起来几乎能处理所有文本类问题。先说sed。打印指定行范围和替换文本是最高频的两个用法sed -n 20,30p app.log打印第20到30行sed -n s/旧内容/新内容/p file只打印发生了替换的行不写回文件sed -i.bak s/旧内容/新内容/g file替换并生成.bak备份。做sed -i之前我的习惯是先不带-i跑一遍确认替换结果正确再落盘加-i.bak生成备份也是个好习惯万一替换错了还能撤回来。sed -n 20,30p app.log sed -n s/旧内容/新内容/p file sed -i.bak s/旧内容/新内容/g fileawk是按列处理的利器。一个很常见的需求从日志里提取某个接口的耗时统计平均值。假设日志每行是“2025-06-01 10:00:00 INFO request_time123ms url/api/user”默认按空格分列我们可以遍历这一行的字段找到request_time那一段把数字抠出来累加。gsub(/[^0-9]/, , $i)的意思是把非数字字符全部替换成空串这样“request_time123ms”就变成了“123”。这一步在处理带单位的数据时几乎是标配。如果只想看哪个路径被访问得最频繁可以配合管道awk {print $NF} access.log | sort | uniq -c | sort -rn | head$NF是最后一列整条管道负责“取末列、排序、统计次数、倒序排列”。awk /request_time/ { for (i 1; i NF; i) { if ($i ~ /^request_time/) { gsub(/[^0-9]/, , $i) sum $i count } } } END { if (count 0) printf avg request_time %.1fms (count%d)\n, sum/count, count } app.log注意awk脚本里经常用到$符号所以整体要放在单引号里不然会被shell先展开。凡是看到awk {...}这种写法记住单引号就是shell和awk之间的隔离带。3. 权限与安全别等出事了才关心这层细节3.1 看懂rwx和umask再决定怎么用chmod和chown权限问题在入门阶段容易被当成“背下来就行”的知识但实际上最常出问题的恰恰是权限。先把rwx的数字含义刻在脑子里r4w2x14217就是rwx5是r-x0是---。所以chmod 754表示属主rwx、属组r-x、其他人r--。chown -R会把目录和里面所有文件的属主属组都改了这个命令要特别小心范围太大、路径写错误伤面会很广。我的原则是执行前先echo一下完整命令确认路径再跑。对目录来说x权限代表能否进入目录所以会出现一种情况某个文件权限是r--理论上有读权限但如果你没有对应目录的x权限依然没法访问。文件权限和目录权限是两层关系排查权限问题时先看目录链。chmod 754 script.sh chown -R appuser:appgroup /data/appumask也值得理解不然你永远不知道为什么默认新建的文件是644、目录是755。umask表示“从默认权限里抹掉哪些位”文件默认666目录默认777再减去umask值就是实际权限。umask 022时666-022644777-022755umask 077时文件变成600目录变成700适合隐私目录。网上很多人图省事直接chmod -R 777这个习惯非常不好777意味着任何人可读可写可执行对配置文件和脚本来说等于把大门敞开。尤其是Web上传目录如果给了执行权限等于给上传木马脚本创造了条件。3.2 特殊权限位、sticky和sudo最小化普通权限之外还有三个特殊权限位setuid4、setgid2、sticky1。它们出现在权限位最前面比如chmod 1777 /tmp这种写法第一位就是特殊权限。/tmp目录必须是1777如果没有sticky位任何一个用户都能删除别人在/tmp里留下的临时文件这就会成为安全隐患。passwd命令带setuid位所以普通用户才能通过它修改 /etc/shadow 里的密码。setuid在方便的同时也是风险点攻击者一旦利用某个setuid程序提权后果很严重所以定期扫描setuid文件是必要的find / -xdev -type f -perm -4000 2/dev/null。正常情况下列出的setuid文件就那么几个系统程序多了就要警觉。这是排查入侵痕迹时的高频检查项。chmod 1777 /tmp # sticky位只有所有者能删除自己的文件 chmod 4755 /usr/bin/demo # setuid位运行时获得属主身份 find / -xdev -type f -perm -4000 2/dev/nullsudo配置也要坚持最小化。visudo里会有类似“user ALL(root) /usr/bin/systemctl restart nginx”的配置意思是只允许指定用户以root身份执行systemctl restart nginx而不是所有命令。平时自己用sudo不觉得什么但一旦服务器上存在多个使用者或服务账号无脑ALL(ALL:ALL) ALL等于把root权限发给所有人。可以在自己的机器上跑一下sudo -l看看当前账号到底被授权了哪些命令往往结果比你想象的多。最小权限说起来是安全口号落到命令上其实就一句话能不给就不给能限定就限定。4. 网络与进程排查一台服务器变慢时该看什么4.1 端口被占用时先别急着kill服务起不来是高频故障最经典的一句话是“address already in use”。遇到这种情况第一反应应该是找出谁占用了端口而不是盲目重启或者kill一串进程。ss -tlnp | grep 8080这条命令参数含义-t只看TCP-l只看监听中的端口-n不做名字解析-p显示进程信息。输出里能看到占用8080的进程名和PID。如果系统没有ss旧一些的机器用netstat -tlnp效果一样。lsof -i:8080也可以。找到PID后需要先判断这个进程是否还有用如果是旧版本服务没退干净可以正常kill如果是其他业务进程贸然kill就会引发新故障。我见过有人为了启动自己的服务把数据库的连接端口进程直接杀掉的事故。所以先看进程名再确认归属最后才动手。ss -tlnp | grep 8080 lsof -i:8080端口连通性测试不要只靠ping。ping测的是ICMP只能说明主机网络通不通不能说明某个端口的服务是否正常。要测试TCP端口就用nc -zv 127.0.0.1 3306-z表示只扫描不发送数据-v显示详细结果返回succeeded就说明端口开着。curl可以进一步验证HTTP服务curl -i http://127.0.0.1:8080/health查看响应头curl -o /dev/null -s -w connect%{time_connect}s total%{time_total}s\n http://127.0.0.1:8080/把响应体丢弃只输出连接耗时和总耗时用来快速判断服务是不是变慢了。nc -zv 127.0.0.1 3306 curl -i http://127.0.0.1:8080/health curl -o /dev/null -s -w connect%{time_connect}s total%{time_total}s\n http://127.0.0.1:8080/4.2 一链命令快速判断CPU、内存、磁盘、IO服务器变慢很多人第一反应是看top但top的信息密度高对新手不友好。我的排查习惯是先跑一条组合命令拿轮廓uptime free -h df -h。uptime看load average三个数字分别代表1分钟、5分钟、15分钟的平均负载。如果1分钟远大于15分钟说明负载是近段时间才涨起来的如果三个数都高说明已经持续一段时间了。free -h重点看available这一列不是看free那一列因为buff/cache在系统内存压力大时是可以释放的。df -h是磁盘空间再跑df -i检查inode。拿到轮廓后根据嫌疑分支细看CPU用top内存用free磁盘用dfIO用iostat -x 1 2重点看util和await。排查目标命令重点看什么CPUtop -bn1 | head -20load、us/sy、id内存free -havailable、swap使用磁盘df -h / df -i空间、inodeIOiostat -x 1 2util、awaittop里有个容易忽略的细节如果load很高但CPU的us/sy都不高id也还有富余那大概率不是CPU运算瓶颈而是在等IO。等IO时wa列会明显偏高这时候要转向iostat -x看磁盘util和await。反过来如果CPU的us接近100%才是真正的CPU密集。配合watch -n 1 free -h; df -h; uptime可以每1秒刷新一次适合在复现问题时挂一个观察窗口。排查性能问题最忌讳凭感觉猜先拿数据定位再用命令验证顺序对了效率自然就高了。5. 进程管理与定时任务让事情按计划运行5.1 看进程状态、安全退出与后台任务进程管理听起来简单但有几个状态和信号的含义不清楚的话容易被表象误导。ps -ef | grep nginx可以看进程是否存在ps aux --sort-%cpu | head -5能按CPU占用排序快速找出谁在消耗资源。STAT列里的状态字符要会看R是运行中、S是睡眠、D是不可中断睡眠通常是在等IO、Z是僵尸进程。D状态进程靠kill是杀不掉的因为它正卡在IO等待里Z状态进程本身已经不消耗资源但需要它的父进程去回收先处理父进程才能弄干净。ps -ef | grep nginx ps aux --sort-%cpu | head -5退出进程时信号选择有讲究。kill -TERM 1234先请求进程正常退出kill -KILL 1234是强制结束属于最后手段。kill默认发TERM让进程自己处理收尾工作只有进程死活不退时才考虑用KILL因为KILL直接让内核终止它来不及释放资源。把kill -9当作第一选择是一种很不好的习惯。后台运行一个长任务常见写法是nohup /opt/start.sh run.log 21 。nohup让进程忽略挂断信号让它在后台运行21把标准错误也定向到同一个日志文件这个位置不能写反。写反了日志还是会打到屏幕上而且后台任务一旦输出过多还可能失控。kill -TERM 1234 kill -KILL 1234 nohup /opt/start.sh run.log 21 日常管理服务优先用systemdsystemctl start nginx启动systemctl enable --now nginx设置开机自启并立即启动systemctl status nginx查看状态journalctl -u nginx -n 50查日志。enable和start是两个动作想一步到位就用enable --now。凡是能用systemd管理的服务就不建议自己写nohup脚本一是自启难保证二是日志、状态管理不如systemd规范。5.2 crontab定时任务写对格式、躲开那些坑定时任务是Linux用来“自动干活”的主要方式。crontab语法不复杂一句话五个星号依次是分、时、日、月、周后面跟命令。30 2 * * * /opt/backup.sh /var/log/backup.log 21表示每天凌晨2点30分执行备份脚本并把输出追加到日志文件0 10 * * 1 /opt/clean_tmp.sh表示每周一10点执行*/5 * * * * /opt/check.sh每5分钟执行一次。写定时任务最怕的是环境变量问题cron执行时的PATH极简可能连/usr/local/bin都不包含脚本里用到命令就用绝对路径或者在脚本开头export PATH。另外百分号%在crontab里有特殊含义用在date命令里要转义或干脆把逻辑写进脚本脚本本身没有执行权限crontab直接执行也会失败不重定向输出时错误信息容易丢失。所以每一条定时任务都要写上重定向到日志文件。30 2 * * * /opt/backup.sh /var/log/backup.log 21 0 10 * * 1 /opt/clean_tmp.sh */5 * * * * /opt/check.sh排错时先看当前用户的定时任务crontab -l。服务日志里经常能捞到执行记录journalctl -u crond --since 10 minutes ago。我排查过几次定时任务不执行最终原因五花八门脚本路径写错、脚本里用了相对路径、权限不对、还有时区问题。基本思路就一条先确认任务有没有被触发再确认脚本执行报什么错。不要一上来就怀疑crontab本身。6. 日志查看与日常效率技巧磨刀不误砍柴工6.1 正确看日志的方式以及logrotate的作用看正在写的日志新手最容易用tail -f /var/log/app.log。less F /var/log/app.log和tail -f类似但它多了一个优势可以随时按CtrlC暂停用/搜索关键字看完按q退出。排查问题的时候经常需要在跟踪和搜索之间切换less F比tail灵活不少。看systemd管理的服务日志用journalctl -u nginx -n 100 --since 1 hour ago查看最近100条、最近1小时的日志journalctl -xe快速查看最近的错误上下文。日志轮转logrotate是另一个容易忽略的点日志如果不做轮转几个月下来就是一个几十G的文件占用磁盘还很难打开。标准做法是写一个logrotate配置daily表示每天轮转一次rotate 7保留最近7份compress是压缩旧日志delaycompress让压缩延迟一天再执行。写完用logrotate -d /etc/logrotate.d/myapp做debug验证。tail -f /var/log/app.log less F /var/log/app.log journalctl -u nginx -n 100 --since 1 hour ago journalctl -xe/var/log/myapp/*.log { daily rotate 7 compress delaycompress missingok }这里有个大坑不要手动mv日志文件就完事。进程一直持有旧日志文件的文件描述符你mv走了旧文件进程依然往旧inode里写磁盘空间根本不会释放。正确的做法是让logrotate管理或者配置里加上copytruncate或者轮转后主动通知进程重开日志文件。这个坑我在线上环境踩过一次当时日志文件mv走之后磁盘占用纹丝不动排查了很久才发现是进程还攥着旧文件描述符。6.2 软链接、硬链接与几个提效小习惯最后说几个影响日常手感的小操作。软链接和硬链接经常被混在一起讲但实际区别要分清ln -s /data/app /opt/app_link创建软链接类似快捷方式可以跨文件系统、可以指向目录目标被删除后链接会变成红链ln /data/file /backup/file_hard创建硬链接多个名字指向同一份数据只能在同一文件系统内建立不能指向目录删除任何一个名字都不影响数据本身只有所有链接都删掉inode才会释放。用硬链接做快照式备份在特定场景下非常省空间两个名字共用同一份数据不会真的复制一份。提效方面alias和history值得单独花两分钟配置。把alias llls -alF、alias grepgrep --colorauto和export HISTTIMEFORMAT%F %T 写进~/.bashrc再source一下日常操作会顺畅很多。history有了时间戳回看历史命令时就能知道哪条命令是什么时候执行的。CtrlR是终端里搜索历史命令的神器输入几个关键字就能把之前敲过的长命令拉回来。我在实际使用中还有一个习惯把常用但复杂的查询写成小脚本放在~/bin目录下然后加入PATH。比如针对本机自定义的服务日志过滤命令写成脚本后一行命令搞定比每次反复翻history舒服得多。这个习惯坚持下来效率提升是实打实的。前面这几篇学习日志下来给我最大的体会不是记住了多少条命令而是遇到问题时能形成一个大概的排查顺序先确认现象再缩小范围最后用命令验证。Linux的实用操作说到底是由大量小技巧拼起来的命令可以随时查但排查思路和操作习惯是慢慢攒出来的。就像这次处理磁盘和日志问题用的都是眼前这几条命令但因为心里有顺序现场不乱问题解决得也快。后面如果还有机会我会继续分享更多实际场景里的处理案例。
阅读完成 · 觉得有帮助?
咨询建站