简介:整理自Linux系统运维实际场景的命令手册,按文件与目录管理、系统管理、网络管理、软件包管理四大板块展开,适合Linux初学者、希望深化掌握常用命令的用户,以及需要频繁维护服务器的技术人员。资源为1个docx格式文档,压缩包约15KB,命令按功能分类编排,便于按需检索。已有129人浏览学习。内容覆盖ls、cp、tar等文件操作,ps、kill、top、crontab等系统管理工具,ssh、scp、netstat、iptables等网络命令,并对比apt、yum、dnf、pacman等不同发行版的包管理差异。每条命令附简洁语法示例,如tail -f实时跟踪日志、grep -r递归搜索文本、chmod设置权限等,可帮助快速理解参数含义与适用场景。既有新手入门所需的系统化梳理,也能作为日常运维的速查手册,对跨平台习惯迁移同样有参考价值。
1. Linux 命令学了就忘:问题不在记不住,在于没有建立排查链路
很多刚接触 Linux 的开发者都有过这种经历:今天记住了tar的压缩参数,明天遇到磁盘写满又不知道怎么定位大文件,后天进程僵住了只会重启机器。打开搜索引擎查命令不丢人,丢人的是同一个问题查了三次还在查。这背后的核心问题不是记忆力,而是缺乏一条从「现象 → 命令 → 结论」的排查链路。
这篇文章不是命令字典,而是把 Linux 日常运维和开发中最常用的命令按「解决什么问题」重新组织一遍。我会从文件操作、文本处理、进程与资源排查、网络诊断这几个维度展开,每一节都给出可以直接复制的命令组合和参数说明,最后单独列一节避坑经验——那些让你半夜爬起来处理线上问题的坑。适合刚上手 Linux 的开发者,也适合用过一段时间但总觉得命令用得不够顺的熟手。读完你能带走的不只是命令,而是一套遇到问题知道该敲什么、敲完怎么看输出的方法论。
2. 文件与目录操作:高频命令的边界在哪里
2.1 用find而不是ls -R:定位文件的标准姿势
很多人在服务器上找一个配置文件,习惯用ls -R /etc一层层翻。这种做法在小目录里没问题,一旦目录层级深、文件多,输出刷屏不说,还得人工去比对路径。find才是干这个活的标准工具。
# 在 /etc 下找所有 .conf 结尾的文件,排除 .bak 备份文件 find /etc -type f -name "*.conf" ! -name "*.bak" 2>/dev/null # 按修改时间找最近 3 天内变过的文件,常用于排查配置被谁改了 find /var/log -type f -mtime -3 2>/dev/null # 按文件大小找超过 500M 的文件,磁盘满的时候第一反应应该是这个 find / -type f -size +500M 2>/dev/null2>/dev/null不是可有可无的装饰。find在遍历目录时会遇到没有读权限的目录,比如/proc、/sys下的某些子目录,不重定向的话错误信息会淹没真正的结果。-type f限定只查普通文件,避免目录、符号链接混进来;-mtime -3表示修改时间在 3 天以内,注意-mtime 3(不带正负号)含义完全不同,它匹配的是恰好 3 天前那一天改过的文件。
2.2du和df的配合:磁盘满了的排查顺序
磁盘告警时,别急着删文件。先分清是「分区满了」还是「某个目录占了大头」,这两件事用的命令不一样。
# 查看各分区使用率,先确认是哪个挂载点告警 df -h # 定位当前目录下各子目录占用,从大往小排 du -sh /* 2>/dev/null | sort -rh | head -20 # 深入到具体目录,比如查出 /var 下谁在涨 du -sh /var/* 2>/dev/null | sort -rh | head -10df -h看的是文件系统层面的占用,du看的是目录树的实际文件大小总和。两者不一致是常态——文件被进程打开后删除了,df显示空间没释放,du却已经看不到这个文件了。这时候要用lsof | grep deleted找出还在占用文件句柄的进程,重启它空间才会真正回来。这是排查磁盘问题时最容易卡住的点。
删除大文件后空间没释放,优先怀疑文件被进程占用;du的结果和df对不上,也别急着困惑,先跑一下lsof +L1看有没有 deleted 状态的文件。
2.3tar打包压缩:参数顺序为什么不能乱写
# 打包并压缩整个目录,排除 node_modules 和 .git tar -czf app_backup.tar.gz /home/user/app \ --exclude=/home/user/app/node_modules \ --exclude=/home/user/app/.git # 解压到指定目录,先看一眼内容再解是好习惯 tar -tzf app_backup.tar.gz | head -20 tar -xzf app_backup.tar.gz -C /tmp/restoretar的参数里,-c(create)、-x(extract)、-t(list)是主操作,只能选一个;-z表示通过 gzip 压缩或解压;-f后面必须紧跟归档文件名。把-f放前面写成tar -cfz在某些版本里会报错或产生意外行为,因为-f后面的参数会被当成文件名。--exclude的路径要写绝对路径或相对路径,而且必须在-f之前指定,顺序写反会导致排除规则不生效。
解压前用-t列出内容检查一下,这是防止 tar 包内路径被恶意构造的实用习惯。
3. 文本处理三剑客:grep、awk、sed 的实战组合
3.1grep的递归搜索:从日志里捞出你要的那条线
日志文件动辄几百 MB,用编辑器打开基本卡死。grep是处理这类问题的第一选择,但裸用grep和用好grep之间差距很大。
# 递归搜索 /var/log 下所有日志,找出包含 ERROR 的行,附带行号 grep -rn "ERROR" /var/log/ --include="*.log" 2>/dev/null # 只看匹配行的前后 5 行,排查异常时看上下文比看单行有用得多 grep -rn -B 5 -A 5 "OutOfMemory" /var/log/app/ 2>/dev/null # 统计某个关键字出现的次数,注意 -c 是统计行数不是次数 grep -rc "timeout" /var/log/nginx/ 2>/dev/null-r是递归,-n显示行号,--include限定文件后缀,避免去搜二进制文件。-B是 before,-A是 after,后面接数字表示行数。排查线上问题时,单行日志往往信息不足,比如 OOM 日志前后的 GC 记录、线程 dump 才能说明问题,所以-B 5 -A 5几乎是我每次排查异常时的标配。
3.2awk取列:别再用 cut 死磕分隔符了
cut对付简单的空格分隔还行,一旦遇到多个空格连续、或者分隔符不固定,cut就废了。awk默认按空白字符切分,多个空格自动合并,这是cut做不到的。
# 从 df 输出中取出使用率超过 80% 的分区 df -h | awk 'NR>1 && $5 ~ /%/ {gsub("%","",$5); if($5 > 80) print $0}' # 从 access.log 中统计每个 IP 的请求次数,按次数降序 awk '{count[$1]++} END {for(ip in count) print count[ip], ip}' access.log | sort -rn | head -20 # 打印第 2 列到第 4 列,逗号作为分隔符 awk -F',' '{print $2, $3, $4}' data.csvawk的基本结构是模式 {动作},NR是当前行号,$1是第一列,$NF是最后一列,NF是本行列数。第二个命令里count[$1]++是典型的关联数组用法,把第一列的 IP 作为 key,每出现一次计数加一;END块在所有行处理完之后执行一次。gsub是 awk 内置的全局替换函数,这里把%符号去掉才能做数值比较。
3.3sed做替换和删除:改配置文件的免编辑器方案
在服务器上改配置,没必要每次都打开 vim。尤其批量替换场景,sed一行命令比手动编辑快得多,也更容易写进脚本里重复执行。
# 将所有 .example.com 替换为 .prod.example.com,直接改文件 sed -i 's/\.example\.com/.prod.example.com/g' /etc/nginx/conf.d/*.conf # 删除所有以 # 开头的注释行,注意保留文件备份 sed -i.bak '/^#/d' /etc/redis/redis.conf # 只在第 10 行到 20 行范围内做替换 sed -i '10,20s/127\.0\.0\.1/0.0.0.0/g' /etc/mysql/my.cnfs是替换命令,格式是s/旧内容/新内容/标志,g表示全局替换,不加g只替换每行第一个匹配。d是删除,前面可以用正则限定行范围。-i直接改文件,-i.bak会在改之前生成一个.bak备份文件——这个习惯值得保留,配置改错了还能一键回滚。
sed的正则里点号.匹配任意字符,要匹配字面上的点必须写成\.,否则example.com会被exampleXcom这样的内容也匹配上,排查时很难发现。
4. 进程、资源与网络排查:从命令到结论
4.1ps和top的组合:找到 CPU 飙高的元凶
# 按 CPU 使用率排序,显示前 10 个进程 ps aux --sort=-%cpu | head -10 # 按内存使用率排序 ps aux --sort=-%mem | head -10 # 查看某个进程的线程,确认是不是单线程卡死 ps -Lp 12345 -o pid,tid,pcpu,commps aux的输出列很多,重点看%CPU、%MEM、TIME三列。TIME是进程累计消耗的 CPU 时间,如果%CPU不高但TIME很大,说明这个进程长期在跑,可能是历史遗留问题;如果%CPU高且TIME也在快速涨,那就是实时性能问题。--sort=-%cpu按 CPU 降序排列,配合head只看前几条,这是定位「哪个进程在抢 CPU」的最快路径。
top更适合交互式观察,按P键按 CPU 排序,按M键按内存排序,按1查看每个核心的负载。如果某个进程 CPU 占用高但ps和top都看不出它在干什么,用strace -p PID跟一下系统调用,往往能发现它在反复读某个文件或者卡在某个系统调用上。
4.2free和vmstat的读法:内存真的不够用吗
# 查看内存总量和剩余量,重点看 available 而不是 free free -h # 每秒刷新一次,连续输出 5 次,观察内存变化趋势 vmstat 1 5free -h的输出里,free列是完全没有被使用的内存,available列是估算的可用于新进程的内存。很多新手看到free很小就以为内存不足,实际上 Linux 会尽量用空闲内存做缓存(buff/cache),这部分内存在需要时会释放给应用程序。判断内存是否够用,看available列,不是free列。
vmstat的si和so列是 swap 换入换出量。如果这两列持续不为 0,说明物理内存确实吃紧,系统在频繁地把内存页换到磁盘上,性能会断崖式下降。r列是等待运行的进程数,持续大于 CPU 核数说明 CPU 也有瓶颈。
4.3ss替代netstat:网络连接排查的新习惯
# 查看所有监听端口和对应的进程 ss -tlnp # 查看所有 TCP 连接,按状态统计 ss -tunap | awk '{print $1}' | sort | uniq -c # 查看某个端口的连接数,常用于排查连接泄漏 ss -tan | grep ":8080" | wc -lss比netstat快很多,-t是 TCP,-u是 UDP,-l是监听状态,-n不做 DNS 反解(避免慢),-p显示进程信息,需要 root 权限。排查线上连接数打满时,重点看TIME_WAIT和CLOSE_WAIT的数量。TIME_WAIT多一般是正常现象,是 TCP 协议主动关闭方的必经状态;CLOSE_WAIT多则说明对端关闭了连接,但本端应用没有调用 close,通常是代码里的连接泄漏,这时候要去查应用而不是调内核参数。
5. Linux 命令避坑指南:六条血泪经验
5.1 删文件用rm -rf的权限边界
现象:某次执行rm -rf /home/user/app/*后,目录下的隐藏文件(.env、.git等)还在。
原因:*在 shell 中默认不匹配以点开头的隐藏文件,这是 shell 的通配符规则,不是rm的问题。
解决:删除隐藏文件时显式指定,比如rm -rf /home/user/app/.[!.]*,或者直接用find /home/user/app -mindepth 1 -delete。后者的好处是能看到删除了哪些路径,-mindepth 1防止把目录本身也删了。另外,rm -rf前先echo /home/user/app/*看一眼展开结果,这个习惯能避免路径写错导致误删。
5.2grep遇到二进制文件时的假结果
现象:grep -r "error" /var/log/刷出一堆奇怪输出,里面有很多乱码字符。
原因:日志目录里混有二进制文件(比如压缩过的轮转日志.gz),grep默认会把二进制文件的内容当文本匹配,输出Binary file xxx matches或者直接把二进制内容打印出来。
解决:加上--include="*.log"限定后缀,或者用-I参数让grep跳过二进制文件。排查轮转日志时,正确做法是先zgrep压缩包里的内容,zgrep "error" /var/log/app.log.gz会自动解压再匹配。
5.3sed -i在 macOS 和 Linux 上的行为差异
现象:在 macOS 上执行sed -i 's/foo/bar/g' file.txt报错,提示invalid option -- 'i'。
原因:macOS 自带的 sed 是 BSD 版本,-i必须跟一个参数(备份后缀),而 Linux 上的 GNU sed 的-i可以不带参数。
解决:在 macOS 上写成sed -i '' 's/foo/bar/g' file.txt(空字符串表示不生成备份),或者统一用perl -pi -e 's/foo/bar/g' file.txt,这个写法在两个平台上行为一致。
5.4 管道和set -o pipefail的隐藏问题
现象:脚本里用grep error app.log | wc -l判断是否有错误,某次 grep 没匹配到内容,脚本依然返回成功。
原因:管道的退出状态默认取最后一个命令(wc -l)的退出状态,grep即使没匹配到内容退出码为 1,管道整体的退出码仍然是 0。
解决:脚本开头加set -o pipefail,让管道中任一命令失败时整体返回失败。如果不想改全局设置,可以单独写grep -q error app.log && echo "has errors",用grep -q的退出码直接判断。
5.5 变量不加引号引发的意外展开
现象:脚本里echo $file_list输出的内容被拆成多行,文件名里有空格的文件被拆成了多个参数。
原因:shell 变量展开后,IFS(默认是空格、制表符、换行)会重新分词,不加双引号的变量会被拆成多个单词。
解决:所有变量展开都加双引号,echo "$file_list";要遍历文件名列表用while IFS= read -r file而不是for file in $file_list。这个问题的隐蔽之处在于本地测试时文件名没有空格没问题,一到真实生产环境就翻车。
5.6kill -9之前先想想有没有更好的方式
现象:某次kill -9掉了 Java 服务进程,重启后数据文件损坏,恢复花了两小时。
原因:-9是 SIGKILL,内核直接回收进程,不给进程任何清理机会。文件写入一半、数据库事务没提交、临时文件没删除,这些都会被中断。
解决:优先kill(默认 SIGTERM),让进程自己处理收尾工作。等待几秒后进程还在,再kill -9也不迟。排查进程为什么退不出去,先看ps -ef确认进程状态,再用strace -p PID看它卡在哪个系统调用上,很多时候问题出在等 IO 而非代码死循环。
6. 把命令变成技巧:Shell 效率的最后一公里
前面几章解决的是「知道用什么命令」,这一节解决的是「减少重复劳动」。熟练的运维和开发在终端里有一个共同特征:很少完整地重敲一条长命令,而是用各种机制把历史命令复用起来。
先配置好history的持久化和去重。默认的.bashrc里历史记录有数量限制,而且多终端窗口互相覆盖,有必要改成追加模式和更大容量。
# ~/.bashrc 里追加以下配置 export HISTSIZE=10000 export HISTFILESIZE=20000 shopt -s histappend export HISTCONTROL=ignoredupshistappend让多个终端会话追加而不是覆盖历史文件,避免开两个窗口时互相覆盖导致历史丢失。ignoredups跳过完全相同的连续命令,减少重复记录。
然后用组合键提升操作效率:Ctrl + R反向搜索历史命令,输入几个关键字直接调出上次用过的长命令;Ctrl + W删除光标前一个单词,Ctrl + U清空整行,比一直按退格键快得多;Alt + .调出上一条命令的最后一个参数,经常配合sudo使用——输入sudo之后按Alt + .会补全上一条命令的完整内容。
最后是一个实用技巧:把自检动作做成一行函数。比如确认端口或服务状态的组合:
# 快速查看某个端口的连接数和进程情况 alias conn='ss -tan | grep ":80" | wc -l; ss -tlnp | grep ":80"'# 一键查看系统负载、内存和磁盘的全局状态 alias sysinfo='uptime; echo "---"; free -h; echo "---"; df -h | grep -v tmpfs'这些 alias 可以存在~/.bashrc里,按自己常用的服务端口做定制。我自己的习惯是每解决一个「查了两次才记住」的问题,就把它固化成一条 alias 或函数,半年下来积累了几十条顺手的小工具,排查问题的速度比翻文档快了一个量级。
曾经因为依赖记忆而不是工具,同一个数据库连接泄漏的问题在处理完一周后又复现了一次,当时没有把排查命令写成脚本,又花了半天重新走了一遍流程。从那以后,凡是超过三步的排查步骤我都会固化成脚本或函数,「这次先记下,下次再整理」最后往往就是没有下次。希望这些命令和习惯能帮你省下重复排查的时间,把精力留在真正需要判断力的地方。
本文还有配套的精品资源,点击获取