自学 Linux 最让人头疼的往往有下面几个问题:命令背了一堆,真到服务器上不知道从哪下手;教程东一块西一块,装完系统就不知道下一步干什么;出了问题只会重启,完全不懂从日志和资源角度排查。这篇文章把这些零散的知识重新组织成一条完整的路径,从环境准备、命令基本功、权限管理,一路走到服务部署、Shell 脚本和故障排查,每个环节都给出可以直接复制执行的命令和验证方式。零基础的同学可以顺着顺序一步步操作,已经有些基础的运维或后端同学,也可以直接跳到第 6、7、8 章查找实战内容和排错思路。
1. Linux 核心概念与学习地图
在敲第一条命令之前,先花几分钟把几个容易混淆的概念理清楚。很多人学了很久还是分不清"内核"和"发行版",导致后面看文档时经常对不上号。
1.1 从内核到发行版
严格来说,Linux 只是指 Linux 内核(Kernel),它负责管理 CPU 调度、内存分配、设备驱动、文件系统这些最底层的事情。而我们在服务器上真正使用的是一整套"操作系统",叫 Linux 发行版(Distribution),它等于:
Linux 内核 + GNU 工具集 + 包管理器 + 初始化系统 + 各类系统服务不同发行版的主要差别在于包管理器和服务管理方式。企业里最常见的是两大类:Red Hat 系(RHEL、CentOS 的替代者 Rocky Linux / AlmaLinux、Fedora)使用rpm/yum/dnf体系;Debian 系(Debian、Ubuntu)使用dpkg/apt体系。两者的命令差异集中在软件安装和部分配置路径上,核心的命令行操作、权限模型、文件系统结构几乎完全一致。
理解了这一点,你就不会被"学 CentOS 还是学 Ubuntu"这类问题卡住。学习阶段选一个顺手的即可,把通用部分学扎实,换发行版只需要重新适应包管理命令。
1.2 "一切皆文件"的设计哲学
Linux 有一个贯穿始终的设计思想:一切皆文件。普通文本是文件,目录是文件,硬盘设备是文件(/dev/sda),内核参数是文件(/proc/sys/net/ipv4/ip_forward),甚至网络连接的状态也能通过文件读取。
这个设计带来的直接好处是:绝大多数操作都可以用同一套工具完成。查看内核参数用cat,修改内核参数用echo >重定向,查看磁盘用文件视角的工具。所以你会发现 Linux 命令数量看起来很多,但底层逻辑高度统一。
与之配套的是 Linux 的目录结构,它遵循 FHS(Filesystem Hierarchy Standard)标准,没有 C 盘、D 盘的概念,所有内容都挂在一棵以/为根的目录树上。
| 目录 | 用途说明 | 新手关注点 |
|---|---|---|
/etc | 系统和服务的配置文件 | 改配置基本都在这里 |
/var | 可变数据,如日志、缓存、数据库文件 | 磁盘满通常先查/var/log |
/usr | 用户级程序与库文件 | 安装的软件多在这里 |
/home | 普通用户的家目录 | 日常操作区域 |
/root | root 用户的家目录 | 权限最高,慎操作 |
/tmp | 临时文件,可能被系统清理 | 不要存重要数据 |
/proc、/sys | 内核和硬件的虚拟文件系统 | 排查性能时常用 |
/dev | 设备文件 | 磁盘、终端都在这里 |
记住这张表,后面看到任何路径你都能大致判断它属于哪一类东西,这是排查问题时非常关键的第一反应。
1.3 零基础到进阶的学习路线
下面这张路线表可以作为你整个学习过程的进度参考。注意顺序不要乱,权限和进程两块是运维的地基,跳过它们直接学 Docker、K8s 会非常痛苦。
| 阶段 | 核心内容 | 达成标准 |
|---|---|---|
| 第一阶段 | 安装系统、目录结构、基础命令 | 能独立登录并操作文件 |
| 第二阶段 | 用户与权限、软件包管理 | 能创建用户并分配合理权限 |
| 第三阶段 | 服务管理、网络配置、防火墙 | 能部署并对外提供 Web 服务 |
| 第四阶段 | Shell 脚本、定时任务 | 能写自动化运维脚本 |
| 第五阶段 | 进程、资源、日志排查 | 能定位常见线上故障 |
| 第六阶段 | 性能调优、容器化、自动化 | 结合业务做工程化落地 |
2. 环境准备与初始化配置
这一步很多人图省事直接跳过,结果后面遇到各种"命令找不到""时间不对""源连不上"的问题。提前做好初始化,能省下大量返工时间。
2.1 三种常见环境的选择
对于自学者,实际可用的环境主要有三种:
第一种是在本机装虚拟机,用 VirtualBox 或 VMware,安装一个 Linux 发行版。优点是随便折腾,快照回滚很方便,适合练习分区、内核参数这类"搞坏了也不心疼"的操作。
第二种是使用云服务器。优点是贴近真实生产环境,有公网 IP,可以练习远程登录、防火墙、域名解析。缺点是涉及费用的部分需要注意,练习完成后记得关机或释放。
第三种是 Windows 下的 WSL2 或 macOS 自带的终端环境。适合只想练命令行、不关心系统层面的同学,启动快、与本地文件互通,但不适合练习服务管理、内核参数这类内容。
我的建议是:虚拟机 + 一台低配云服务器组合使用。虚拟机用来练系统和分区,云服务器用来练部署和远程运维。
2.2 安装时的关键选项
安装过程中有几个选项需要留意,它们会直接影响你后续的学习体验:
内存分配建议不低于 2GB,否则部分图形化安装和编译场景会卡。磁盘建议 20GB 起,如果在虚拟机里练习 LVM 或分区,可以给到 40GB。
分区方面,入门阶段用自动分区完全够用,但建议了解一下三个核心挂载点的意义:/是根分区,/boot存放内核和引导文件,swap是交换分区(内存不足时的兜底)。生产环境通常会把/var和/home单独划分,避免日志写满拖垮整个根分区。
软件选择上,优先选"最小化安装"(Minimal Install)。最小化安装只带必要组件,能让你清楚地知道每个软件是自己装的,而不是系统预装的,排查问题时干扰更少。
2.3 首次登录后的基础配置
系统装完,先做一轮基础配置。以下命令在 RHEL 系和 Debian 系上基本通用,个别地方我会标注差异。
第一步,确认系统版本,避免后面查文档对不上。
# 查看发行版信息 cat /etc/os-release # 查看内核版本与架构 uname -r uname -m第二步,设置主机名和时区。主机名在集群环境下非常重要,日志和监控都靠它区分节点。
# 设置主机名(立即生效 + 开机保持) hostnamectl set-hostname web-node-01 # 设置时区为东八区 timedatectl set-timezone Asia/Shanghai # 验证时间与 NTP 同步状态 timedatectl status第三步,更新系统并配置软件源。首次安装后先做一次全量更新,能规避不少已知问题。
# RHEL / Rocky / AlmaLinux 系 sudo dnf update -y # Debian / Ubuntu 系 sudo apt update && sudo apt upgrade -y软件源如果下载速度慢,可以替换为就近的镜像站。以 Debian 系为例,配置文件在/etc/apt/sources.list;RHEL 系的仓库文件在/etc/yum.repos.d/目录下。修改前先备份原文件,这是个必须养成的习惯:
# 修改任何系统配置前,先备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak第四步,创建日常使用的普通用户并授予 sudo 权限。生产环境千万不要长期用 root 直接操作,原因在第 4 章会详细说。
# 创建用户并设置密码 sudo useradd -m -s /bin/bash devuser sudo passwd devuser # 加入 wheel 组(RHEL 系),Debian 系为 sudo 组 sudo usermod -aG wheel devuser配置完成后退出重新登录,用whoami和sudo -l验证身份与授权是否生效。
3. 命令行基本功:文件与文本操作
命令行的核心其实只有三件事:找到文件、看懂内容、改动它。把这三件事练熟,80% 的日常操作就没问题了。
3.1 命令行的组成结构与通配符
一条命令的标准结构是:命令 [选项] [参数]。选项分短选项(-l)和长选项(--long),多个短选项可以合并写,比如ls -lh等价于ls -l -h。
通配符是提升效率的关键。*匹配任意多个字符,?匹配单个字符,[abc]匹配括号内任一字符。举几个实际场景:
# 列出所有 .log 结尾的文件 ls -lh *.log # 删除 2025 年 3 月的日志(先 ls 确认再删!) ls -lh app-2025-03-*.log # 匹配 a.log、b.log、c.log ls -l [abc].log这里必须强调一点:任何带通配符的删除命令,都要先用ls预览结果,确认无误后再把ls换成rm。这是运维事故里出现频率最高的操作之一。
3.2 文件浏览与查找
查看文件内容,按场景选工具:
cat file.txt # 一次性输出,适合小文件 less file.txt # 分页查看,大文件首选,q 退出 head -n 20 file.txt # 看前 20 行 tail -n 20 file.txt # 看后 20 行 tail -f /var/log/messages # 实时跟踪日志,排查问题必备less内部还支持/关键字搜索、G跳末尾、g跳开头,比cat实用得多,建议养成习惯。
按名称或内容查找文件,find和grep是两个必须掌握的命令:
# 按名称查找:在 /etc 下找所有 .conf 文件 find /etc -name "*.conf" -type f # 按大小查找:找 /var 下大于 100MB 的文件 find /var -type f -size +100M -exec ls -lh {} \; # 按修改时间查找:找 7 天内修改过的文件 find /opt -type f -mtime -7 # 按内容查找:在目录下递归搜索关键字 grep -rn "listen 80" /etc/nginx/find的-exec参数配合{}占位符和\;结尾,可以对查找到的文件批量执行命令,这是自动化脚本里的高频写法。
3.3 文件操作与软硬链接
创建、复制、移动、删除这套基础操作不多说,重点讲两个容易出错的地方。
第一个是cp和mv对目录的处理。cp复制目录必须加-r,mv不需要。另外cp -a会保留权限、时间戳、软链接等属性,备份配置文件时推荐用它。
第二个是软链接(symbolic link)和硬链接(hard link)的区别,这个概念面试和实操都经常考:
# 创建软链接:类似 Windows 快捷方式,源文件删除后链接失效 ln -s /opt/app/releases/v1.2.0 /opt/app/current # 创建硬链接:指向同一个 inode,删除源文件不影响访问 ln /data/file.txt /data/file_hardlink.txt软链接可以跨分区、可以指向目录,日常使用最多,典型场景就是上面这种"版本目录 + current 软链"的发布方式,回滚时只要切换软链接指向即可,不用重新拷贝文件。硬链接不能跨分区、不能指向目录,但删除任一链接都不影响数据本身,只有所有硬链接都被删除,文件数据才真正释放。
3.4 文本处理三剑客:grep、sed、awk
这三个工具的定位不同:grep负责筛选行,sed负责编辑替换,awk负责按列处理。运维排查日志,基本就是这三者的组合。
# grep:筛选包含 ERROR 的行,并显示行号、忽略大小写 grep -in "error" /var/log/app/app.log # grep 反向匹配:排除包含 DEBUG 的行 grep -v "DEBUG" app.log # sed:把配置文件中的 8080 替换为 9090,-i 表示直接修改原文件 sed -i 's/8080/9090/g' /etc/app/app.conf # sed:只打印第 10 到 20 行 sed -n '10,20p' app.log # awk:按空格分隔取第 1 列和第 9 列(常用于分析访问日志) awk '{print $1, $9}' /var/log/nginx/access.log # awk:统计访问日志中每个 IP 的请求次数,取前 10 awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10最后那条命令是排查"某个 IP 疯狂刷接口"的经典写法,拆开看就是:取第一列 IP → 排序 → 去重计数 → 按次数倒序 → 取前 10 条。理解了这个管道串联的思路,你就能自己组合出各种统计命令。
注意sed -i会直接修改原文件,生产环境执行前务必先不带-i跑一遍看输出结果,或者先备份文件。
4. 用户、权限与安全边界
Linux 是多用户系统,权限模型是整个系统安全的基础。这一章的内容看起来枯燥,但线上事故有相当一部分源于权限配置不当。
4.1 用户与用户组管理
Linux 中每个进程都以某个用户身份运行,这个身份决定了它能访问哪些资源。用户分为三类:root(超级用户,UID 为 0)、系统用户(UID 通常小于 1000,给服务进程使用)、普通用户(UID 1000 起)。
# 查看当前登录用户与 UID id # 创建用户,-m 创建家目录,-s 指定登录 shell sudo useradd -m -s /bin/bash deploy # 修改用户密码 sudo passwd deploy # 创建用户组并把用户加进去 sudo groupadd appgroup sudo usermod -aG appgroup deploy # 查看用户所属的所有组 groups deploy # 锁定/解锁账号(人员离职时用锁定而不是删除) sudo usermod -L deploy sudo usermod -U deploy这里有个细节值得注意:usermod -aG中的-a是 append 的意思,如果不加-a,用户原有的附加组会被覆盖掉。这个坑被踩过的人非常多。
4.2 权限位 rwx 与数字换算
用ls -l看到的权限串形如-rw-r--r--,共 10 位。第 1 位是文件类型(-普通文件、d目录、l软链接),后面 9 位每 3 位一组,分别对应属主(user)、属组(group)、其他人(other)。
| 权限 | 对文件的意义 | 对目录的意义 | 数字 |
|---|---|---|---|
| r | 读取文件内容 | 列出目录内文件名 | 4 |
| w | 修改文件内容 | 在目录内创建/删除文件 | 2 |
| x | 执行文件 | 进入目录(cd) | 1 |
一个常见误区是认为目录的w权限决定能否修改目录里的文件,实际上目录的w决定的是能否在目录内增删文件本身,跟文件内容无关。理解了这一点,就明白为什么有时候文件权限是 777 却依然删不掉——因为父目录没有写权限。
日常最常用的几个权限组合:
chmod 644 file.txt # 属主读写,其他只读,配置文件、静态资源常用 chmod 755 script.sh # 属主读写执行,其他读执行,脚本和目录常用 chmod 600 id_rsa # 仅属主读写,私钥必须这样设 chmod 700 private_dir # 仅属主可进入,敏感目录递归修改目录权限用-R,但要注意chmod -R会把目录下的所有文件一起改掉,可能破坏已有的权限设计。更稳妥的做法是分开处理:
# 目录设为 755 find /var/www/html -type d -exec chmod 755 {} \; # 文件设为 644 find /var/www/html -type f -exec chmod 644 {} \;修改属主属组用chown:
sudo chown -R www-data:www-data /var/www/html # Debian 系 sudo chown -R nginx:nginx /usr/share/nginx/html # RHEL 系4.3 sudo 与最小权限原则
不要把 root 密码给所有人,也不要用 root 直接跑业务进程。正确做法是通过 sudo 做权限委派,只授予必要的命令。
/etc/sudoers是 sudo 的主配置文件,必须用visudo编辑,因为它会在保存时检查语法,语法错误会导致所有 sudo 失效,直接把自己锁在系统外面。
sudo visudo在文件中可以这样配置:
# 允许 deploy 用户以 root 身份执行所有命令(免密) deploy ALL=(ALL) NOPASSWD: ALL # 更安全的做法:只允许执行特定命令 deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx, /bin/systemctl status nginx在实际项目中更推荐后一种写法。运维人员的职责边界应该由配置来约束,而不是靠"大家都清楚"这种口头约定。
4.4 权限相关的常见问题
第一类是"命令找不到",但明明装好了。这通常是 PATH 问题,或者软件装在了非标准路径。用which、whereis定位,或者直接find / -name "命令名" -type f。也可能是执行权限缺失,chmod +x即可。
第二类是脚本报 "Permission denied",检查两处:文件本身有没有x权限,以及脚本所在的分区是不是被挂载成了noexec。
第三类是文件能读不能写,即使 chmod 777 也不行,这往往是 SELinux 或文件系统只读导致的。先用getenforce查看 SELinux 状态,再确认mount输出里该分区是不是ro。
5. 软件包管理与系统服务
装软件和管服务是运维的日常操作。这一章把两种发行版的管理方式对齐讲,方便你在不同环境下迁移。
5.1 包管理器:dnf/yum 与 apt
RHEL 系使用dnf(CentOS 7 时代是yum,dnf是其升级版,多数命令兼容),Debian 系使用apt。
# RHEL / Rocky 系 sudo dnf install -y nginx # 安装 sudo dnf remove -y nginx # 卸载 sudo dnf search nginx # 搜索 sudo dnf info nginx # 查看包信息 sudo dnf list installed | grep nginx # 查看是否已安装 sudo dnf provides */netstat # 查询某命令属于哪个包 # Debian / Ubuntu 系 sudo apt install -y nginx sudo apt remove -y nginx sudo apt search nginx sudo apt show nginx dpkg -l | grep nginx sudo apt-file search /usr/bin/netstatdnf provides和apt-file search这两个命令非常实用,它们解决的是"命令存在但提示 not found,我不知道该装哪个包"这个高频问题。apt-file需要先apt install apt-file && apt-file update。
5.2 systemd 服务管理
现代 Linux 发行版基本都用 systemd 作为初始化系统,systemctl是管理入口。
# 启动、停止、重启 sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl restart nginx # 设置开机自启 / 取消开机自启 sudo systemctl enable nginx sudo systemctl disable nginx # 查看服务状态(最常用,能看到最近几行日志) systemctl status nginx # 列出所有运行中的服务 systemctl list-units --type=service --state=running # 列出所有启动失败的服务 systemctl --failed # 重新加载配置(不重启进程) sudo systemctl reload nginxrestart和reload的区别需要明确:reload只让进程重新读取配置,连接不中断;restart是完全停掉再启动,会断开现有连接。生产环境中,Nginx 这类支持平滑重载的服务应优先用reload,并先执行配置检查。
自己写的程序也可以交给 systemd 托管,只要写一个 unit 文件。这是让脚本"变成服务"的关键步骤:
# 文件路径:/etc/systemd/system/myapp.service [Unit] Description=My Application Service After=network.target [Service] Type=simple User=deploy Group=deploy WorkingDirectory=/opt/myapp ExecStart=/opt/myapp/start.sh Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target写完后执行sudo systemctl daemon-reload让 systemd 重新加载,然后enable --now启动并设为开机自启。其中Restart=on-failure表示进程异常退出时自动拉起,这是保证服务可用性的基础配置。
5.3 防火墙与端口开放
服务装好了却访问不了,十有八九是防火墙没放行。RHEL 系默认使用firewalld,Debian 系常用ufw。
# firewalld 常用操作 sudo firewall-cmd --state # 查看状态 sudo firewall-cmd --list-all # 查看当前规则 sudo firewall-cmd --add-service=http --permanent # 永久放行 HTTP sudo firewall-cmd --add-port=8080/tcp --permanent # 永久放行 8080 sudo firewall-cmd --reload # 重载使规则生效 # ufw 常用操作 sudo ufw status sudo ufw allow 80/tcp sudo ufw allow 22/tcp sudo ufw enable这里最容易踩的坑是:放行规则加了但没有--reload,或者忘了加--permanent导致重启后规则丢失。另外如果用云服务器,还需要在云平台的安全组里放行对应端口,两层防火墙都要检查。
6. 完整实战:从零部署一个 Nginx 服务
理论铺垫够了,这一章做一次完整的端到端部署。整套流程走完,你对"装软件 → 配服务 → 放行端口 → 验证 → 开机自启"这条链路就有了肌肉记忆。
6.1 部署前的检查
先确认环境状态,避免装到一半发现磁盘不够或者端口被占。这个习惯在实际项目中非常重要。
# 确认系统版本 cat /etc/os-release | head -3 # 检查磁盘剩余空间(根分区至少留 2GB) df -h / # 检查 80 端口是否已被占用 sudo ss -lntp | grep ':80' # 确认防火墙状态 sudo firewall-cmd --state 2>/dev/null || sudo ufw status6.2 安装 Nginx
# RHEL / Rocky 系 sudo dnf install -y nginx # Debian / Ubuntu 系 sudo apt update && sudo apt install -y nginx安装完成后启动服务并设置开机自启:
sudo systemctl enable --now nginx systemctl status nginxenable --now是enable和start的组合写法,一步搞定开机自启和立即启动,日常用得最多。
6.3 配置站点与目录
以部署一个静态站点为例。先准备站点目录和页面文件:
# 创建站点目录 sudo mkdir -p /var/www/mysite # 写入一个测试页面 sudo tee /var/www/mysite/index.html > /dev/null <<'EOF' <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Linux 部署验证</title> </head> <body> <h1>Nginx 部署成功</h1> <p>This page is served by Nginx on Linux.</p> </body> </html> EOF # 修正属主,避免 Nginx 读取时权限不足 sudo chown -R nginx:nginx /var/www/mysite 2>/dev/null || sudo chown -R www-data:www-data /var/www/mysite然后写一个独立的配置文件,而不是直接改主配置。这是工程化的关键习惯,把自定义配置和系统默认配置分离,升级软件时不会互相覆盖。
# 文件路径:/etc/nginx/conf.d/mysite.conf server { listen 80; server_name localhost; root /var/www/mysite; index index.html; access_log /var/log/nginx/mysite_access.log; error_log /var/log/nginx/mysite_error.log; location / { try_files $uri $uri/ =404; } }几个参数说明一下:listen 80是监听端口;server_name用于按域名分流,本地测试写 localhost 即可,生产环境填实际域名;root是站点根目录;try_files让 Nginx 按顺序查找文件,都找不到返回 404。
6.4 配置校验、放行端口与验证
修改 Nginx 配置后一定要先测试再重载,这是避免服务中断的标准动作:
# 校验配置语法 sudo nginx -t # 语法正确则平滑重载 sudo systemctl reload nginx # 放行 80 端口 sudo firewall-cmd --add-service=http --permanent sudo firewall-cmd --reload验证环节分三层,从内到外逐层排除:
# 第一层:本机回环,验证 Nginx 本身是否正常 curl -I http://127.0.0.1 # 第二层:本机 IP,验证监听地址是否正确 curl -I http://$(hostname -I | awk '{print $1}') # 第三层:外部访问,验证防火墙和安全组 # 在浏览器打开 http://服务器IP预期输出中应该能看到HTTP/1.1 200 OK和Server: nginx字样。
6.5 结果说明与排错定位
如果前两层通、第三层不通,问题在防火墙或云安全组;如果第一层就不通,看systemctl status nginx和/var/log/nginx/error.log;如果返回 403,检查站点目录权限和 SELinux;如果返回 404,检查root路径和index配置是否匹配。
这套"从内到外、逐层验证"的思路,适用于几乎所有网络服务的排查,不只是 Nginx。
7. Shell 脚本与定时任务自动化
运维的价值很大程度体现在"把重复劳动变成脚本"。这一章从脚本骨架讲到实际可用的日志清理脚本。
7.1 脚本的标准骨架
一个健壮的 Shell 脚本,开头至少要有这几行:
#!/bin/bash # 脚本名:clean_logs.sh # 功能:清理指定目录下超过 N 天的日志文件 # 用法:./clean_logs.sh /var/log/app 7 set -euo pipefail#!/bin/bash是 shebang,指定解释器。set -euo pipefail是三个开关的组合:-e表示任一命令失败立即退出,-u表示使用未定义变量时报错,-o pipefail表示管道中任一环节失败都算整体失败。这三个开关能帮你提前发现大量隐藏错误,脚本里强烈建议加上。
7.2 变量、条件与循环
Shell 中的变量赋值等号两边不能有空格,这是最常见的语法错误。
#!/bin/bash set -euo pipefail # 变量定义 LOG_DIR="/var/log/app" KEEP_DAYS=7 STAMP=$(date +%Y%m%d-%H%M%S) # 参数校验:必须传两个参数 if [ $# -ne 2 ]; then echo "用法: $0 <日志目录> <保留天数>" exit 1 fi LOG_DIR="$1" KEEP_DAYS="$2" # 目录存在性校验 if [ ! -d "$LOG_DIR" ]; then echo "错误: 目录不存在 -> $LOG_DIR" exit 2 fi echo "[$STAMP] 开始清理 $LOG_DIR 中超过 $KEEP_DAYS 天的日志"条件判断里有两个细节要注意:[后面和]前面必须有空格;变量引用建议加双引号,否则变量为空时会导致判断语句语法错误。
循环的常见形式:
# 遍历数组 SERVICES=("nginx" "sshd" "crond") for svc in "${SERVICES[@]}"; do if systemctl is-active --quiet "$svc"; then echo "$svc 运行中" else echo "$svc 未运行" fi done # 遍历文件 for f in /var/log/app/*.log; do [ -f "$f" ] || continue echo "处理文件: $f" done7.3 实战:带日志的日志清理脚本
下面这个脚本比较完整,包含参数校验、安全保护、执行记录和错误处理,可以直接拿去改。
#!/bin/bash # 文件路径:/opt/scripts/clean_logs.sh # 功能:清理指定目录下超过 N 天的 .log 文件 # 用法:./clean_logs.sh /var/log/app 7 set -euo pipefail LOG_DIR="${1:-}" KEEP_DAYS="${2:-7}" SCRIPT_LOG="/var/log/clean_logs.log" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$SCRIPT_LOG" } # 参数校验 if [ -z "$LOG_DIR" ]; then echo "用法: $0 <日志目录> [保留天数,默认 7]" exit 1 fi if [ ! -d "$LOG_DIR" ]; then log "错误:目录不存在 -> $LOG_DIR" exit 2 fi # 安全保护:禁止对根目录等敏感路径执行 case "$LOG_DIR" in /|/etc|/usr|/bin|/boot|/dev) log "拒绝操作敏感目录 -> $LOG_DIR" exit 3 ;; esac log "开始清理,目录=$LOG_DIR,保留天数=$KEEP_DAYS" # 先统计,再删除,便于审计 COUNT=$(find "$LOG_DIR" -type f -name "*.log" -mtime +"$KEEP_DAYS" | wc -l) log "匹配到 $COUNT 个待清理文件" if [ "$COUNT" -eq 0 ]; then log "无需清理" exit 0 fi find "$LOG_DIR" -type f -name "*.log" -mtime +"$KEEP_DAYS" -print -delete >> "$SCRIPT_LOG" 2>&1 log "清理完成"脚本里有几个设计值得单独说明:${1:-}和${2:-7}是带默认值的参数展开,避免set -u下未定义变量报错;case语句做敏感目录拦截,这是删除类脚本的安全底线;先用find ... | wc -l统计再执行删除,两者结合相当于一次"干跑预览";-print -delete会把删除的文件路径记录到日志,出问题能追溯。
授权并测试:
chmod +x /opt/scripts/clean_logs.sh /opt/scripts/clean_logs.sh /var/log/app 77.4 crontab 定时任务
脚本写好了,用 crontab 让它定时跑。cron 的时间格式是五位:分 时 日 月 周。
# 编辑当前用户的定时任务 crontab -e # 查看 crontab -l# 每天凌晨 3 点执行日志清理 0 3 * * * /opt/scripts/clean_logs.sh /var/log/app 7 >> /var/log/clean_logs_cron.log 2>&1 # 每 5 分钟执行一次健康检查 */5 * * * * /opt/scripts/health_check.sh >> /var/log/health.log 2>&1 # 每周一 2 点执行 0 2 * * 1 /opt/scripts/weekly_report.sh >> /var/log/weekly.log 2>&1crontab 的坑相当集中,主要有四个:
第一,执行环境不同。cron 执行时的 PATH 比登录 shell 精简得多,脚本里用到的命令最好写绝对路径,或者在 crontab 顶部声明 PATH。
第二,必须重定向输出。不重定向的话,输出会以邮件形式堆积或者直接丢失,排查时无从下手。>> xxx.log 2>&1是标准写法。
第三,脚本需要执行权限,并且 shebang 要正确。
第四,时间不准,先确认timedatectl与时区设置正确,再排查 cron 服务是否运行(systemctl status crond或systemctl status cron)。
8. 进程、资源与日志排查
这是运维能力的分水岭。能装服务的人很多,能在一台卡住的服务器上快速定位原因的人不多。这一章给出一套可以直接照着走的排查路径。
8.1 进程查看:ps 与 top
排查问题的第一反应应该是:谁在吃资源。
# 查看所有进程,按 CPU 排序取前 10 ps aux --sort=-%cpu | head -11 # 按内存排序 ps aux --sort=-%mem | head -11 # 查找指定进程 ps -ef | grep nginx # 按名称精确匹配,避免 grep 自身混进来 pgrep -a nginxtop是动态查看工具,进去之后记住几个快捷键就够了:P按 CPU 排序,M按内存排序,1展开每个 CPU 核心,q退出。
top -b -n 1 | head -20 # 一次性输出,适合写进脚本看top的输出时,重点看三个值:load average(1/5/15 分钟平均负载,超过 CPU 核数就说明有排队)、%Cpu(s)中的us(用户态占比,高说明业务在算)和sy(内核态占比,高说明系统调用或 IO 有问题)、%MEM高的进程。如果wa(IO 等待)很高,说明瓶颈在磁盘而不是 CPU。
8.2 磁盘与内存:df、du、free
磁盘满是最常见的线上故障之一,而且往往连锁反应很大——日志写不进去、数据库无法写入、服务直接挂掉。
# 查看各分区使用率 df -h # 查看 inode 使用率(小文件太多时,df -h 看着有空间但写不进去) df -i # 查看某目录下各子目录占用大小,按大小排序取前 10 du -sh /var/* 2>/dev/null | sort -rh | head -10 # 找大文件 find / -type f -size +500M -exec ls -lh {} \; 2>/dev/null这里有个经典陷阱:df -h显示还有空间,但文件就是创建不了。这通常是 inode 耗尽,用df -i确认。另一种情况是文件被删除但进程还持有句柄,空间没释放:
# 查找已删除但仍被占用的文件 sudo lsof | grep deleted解决办法是重启持有该文件的进程,而不是重启整台机器。
内存查看:
free -h重点看available这一列,而不是free。free数值小是正常的,因为 Linux 会尽量把空闲内存用作缓存,available才是真正可分配给新进程的量。如果available很低且swap使用量持续增长,说明内存不足,需要考虑扩容或优化程序。
8.3 网络排查:ss、curl、ping
服务访问不通,按"网络层 → 传输层 → 应用层"逐层排查。
# 确认端口监听状态,-l 监听 -n 数字显示 -t TCP -p 显示进程 sudo ss -lntp # 查看某端口的连接数 ss -ant | grep ':80' | wc -l # 测试连通性 ping -c 4 8.8.8.8 # 测试端口是否可达(不依赖 ping) nc -zv 目标IP 80 # 测试 HTTP 服务 curl -I http://目标IP curl -v http://目标IP # 详细模式,能看到完整的请求响应过程 # 路由追踪 traceroute 目标域名ss已经基本取代了老的netstat,输出更快也更清晰。如果某端口在ss里能看到监听,但外部连不上,问题基本锁定在防火墙或安全组;如果ss里根本没有监听,说明服务没起来或监听地址不对(比如只监听了127.0.0.1而没监听0.0.0.0)。
8.4 日志定位:journalctl 与文件日志
日志是排查问题的第一手证据。systemd 管理的服务,日志统一走 journal。
# 查看某服务的日志 journalctl -u nginx # 实时跟踪 journalctl -u nginx -f # 只看最近 100 行 journalctl -u nginx -n 100 # 按时间范围过滤 journalctl -u nginx --since "2025-01-01 10:00:00" --until "2025-01-01 11:00:00" # 只看错误级别 journalctl -u nginx -p err # 查看本次开机以来的日志 journalctl -b如果日志量很大,可以用--disk-usage查看占用,用journalctl --vacuum-time=7d清理 7 天前的日志,防止把磁盘写满。
对于应用自己写的日志文件(如/var/log/nginx/access.log),还是回到tail -f加grep的组合。定位具体时间点的异常,可以这样组合:
# 找出 10 点到 11 点之间的 ERROR,并显示上下文各 3 行 grep -n "ERROR" app.log | grep "2025-01-01 1[01]:" # 统计各类异常出现的次数 grep -o "Exception[A-Za-z]*" app.log | sort | uniq -c | sort -rn日志排查的核心思路是:先缩小时间窗口,再用关键字过滤,最后看上下文。不要一上来就cat整个文件,几万行的输出除了刷屏没有任何帮助。
9. 常见问题与排查清单
下面这张表整理了初学者和初中级运维最常遇到的十几类问题,建议收藏后按图索骥。
| 问题现象 | 常见原因 | 排查与解决思路 |
|---|---|---|
command not found | 命令未安装 / PATH 不含该路径 | which定位,dnf provides或apt-file查所属包 |
Permission denied | 缺执行权限 / 文件系统 noexec / SELinux | ls -l查权限,mount查挂载参数,getenforce查 SELinux |
| 服务启动即退出 | 配置语法错误 / 端口占用 / 依赖未就绪 | systemctl status加journalctl -u看具体报错 |
| 端口已监听但外部访问不了 | 防火墙未放行 / 云安全组未开 | firewall-cmd --list-all,检查云平台安全组 |
| 磁盘突然 100% | 日志未轮转 / 大文件堆积 | du -sh /*逐层定位,find找大文件 |
df -h有空间却写不进去 | inode 耗尽 / 文件句柄未释放 | df -i查 inode,lsof | grep deleted查僵尸句柄 |
| 内存不足触发 OOM | 程序内存泄漏 / JVM 堆设置过大 | free -h看 available,journalctl -k | grep -i oom确认 |
| 系统负载高但 CPU 空闲 | IO 瓶颈 / 大量进程阻塞 | top看wa,iostat -x 1看磁盘 IO |
| 定时任务不执行 | 环境变量缺失 / 未加执行权限 / 时间不对 | 脚本内用绝对路径,重定向输出看日志 |
| 修改配置后不生效 | 未 reload / 配置被覆盖 | systemctl reload,nginx -t校验,确认配置加载顺序 |
| 中文字符乱码 | 系统 locale 未设置 | locale查看,localectl set-locale设置 |
| SSH 连接慢或超时 | DNS 反解 / 网络策略限制 | sshd_config中UseDNS no,检查网络链路 |
| 时间不一致 | NTP 未同步 / 时区错误 | timedatectl检查,启用chronyd或systemd-timesyncd |
| 软链接失效 | 源文件被删除或移动 | ls -l看指向,readlink -f看实际路径 |
排查时有几条通用原则值得反复强调:先确认现象再动手,不要凭猜测改配置;一次只改一个变量,同时改多处就无法判断是哪一处生效;改动前先备份,配置文件.bak是零成本保险;优先看日志,几乎所有错误信息都在日志里写好了,只是没被读到。
10. 最佳实践与进阶路线
最后这一部分讲讲工程上的习惯,这些内容在任何教程里都不太显眼,但在实际工作中决定了一个人是不是"靠谱"。
操作安全方面,永远不要在不确定的情况下执行rm -rf;删除前用ls预览;重要操作前先做快照或备份;生产环境变更前在测试环境验证一遍;涉及数据库和文件系统的破坏性操作,必须确认有可回滚的方案。这些都是用事故换来的经验,不必自己再交一次学费。
权限管理方面,遵循最小权限原则。业务进程用独立的非 root 用户运行;数据库账号按需授权,不要图省事给ALL PRIVILEGES;sudo 配置细化到具体命令;SSH 禁止 root 直接登录,改用普通用户加 sudo。这些配置在/etc/ssh/sshd_config里都有对应开关。
配置管理方面,把"手工改服务器"变成"代码化管理"。至少做到配置文件纳入版本控制,重要的配置文件在系统里用软链接指向版本库中的实际文件;自定义配置与系统默认配置分离,放在conf.d这类目录下;用 Ansible 之类的工具做批量配置分发,避免一台台手工改导致环境漂移。
日志管理方面,所有服务都要配置日志轮转,用logrotate控制单个文件大小和保留份数,这是防止磁盘被打满的根本手段;关键操作要留审计日志;日志内容要包含时间、来源、请求标识,便于串联排查。
脚本编写方面,脚本开头加set -euo pipefail;变量加双引号;用绝对路径;重要的脚本带上参数校验和敏感路径保护;删除类脚本先输出再执行;脚本本身也纳入版本管理。这些习惯让脚本从"一次性工具"变成"可维护资产"。
继续往下走的学习路线,大致有这么几个方向:一是深入 systemd 与内核参数调优,理解sysctl、ulimit、cgroup 的作用;二是网络与安全方向,掌握 iptables/nftables 规则、TLS 证书管理、SSH 加固;三是自动化方向,学 Ansible 做配置管理,用脚本或 CI 工具做发布流水线;四是容器化方向,Docker 与 Kubernetes 本质上是对 Linux 的 namespace、cgroup、文件系统的上层封装,前面的基础越扎实,这部分学起来越顺。
在学习方法上有一个建议:不要试图"背完命令再动手"。正确的顺序是带着任务去查命令,用一次记一次。比如今天的任务是"部署一个 Nginx 并让外网能访问",过程中你自然会用到dnf、systemctl、firewall-cmd、curl、ss,这些命令在真实场景里用过一遍,比抄十遍笔记都管用。建议给自己准备一台可以随便折腾的机器,把本文第 6、7、8 章的流程完整走两遍,第一遍照着做,第二遍合上文章自己做,遇到卡住的地方再回来查——这个过程走完,Linux 的基础操作基本就成为你的能力了。