
1. 学习笔记 day02从能敲命令到会干活的进阶之路昨天我们把 Linux 环境跑起来学会了怎么进出目录、怎么看文件算是正式踏进了这个黑乎乎的命令行世界。今天这篇 day02 笔记我会延续第一天的节奏专门梳理那些日常使用频率最高、面试也常被问到的命令和概念包括用户与权限、进程管理、文本处理、系统状态查看、网络排查最后再搭配几个我实际工作中踩过的坑和故障案例。学完今天这些内容你就不再是只会敲ls的小白了至少能处理一些真实的运维场景看得懂系统日志也敢动手去排查问题了。这篇笔记适合刚学完基础命令、想往运维或嵌入式方向走的同学也适合那些命令行用了很久但一直靠死记硬背、没搞清楚底层逻辑的朋友。我尽量不堆砌命令列表而是把每个命令放到实际场景里讲告诉你为什么用、什么时候用、用了之后看什么。毕竟 Linux 这东西光背命令是记不住的你得理解它背后的设计思路——一切皆文件、权限驱动、进程协作顺着这条线往下走命令自然就串起来了。先说一下今天笔记的定位day02 不碰编译内核、不搞驱动开发也不深入源码专注把“日常管理和排障”这层打扎实。具体内容包括用户与文件权限、进程与后台任务、文本与日志处理、系统资源查看、网络工具以及几个我自己遇到过的真实故障案例。每段我都会给出命令示例和执行思路你看完可以直接在自己的虚拟机里练一遍。2. 用户与权限Linux 安全模型的基石2.1 用户、组、权限位到底怎么配合很多新手刚接触 Linux 权限时最困惑的一件事就是明明文件是自己的为什么改了没效果为什么别人能读我不能读这背后其实就是 Linux 最核心的安全模型——用户User、组Group、其他Other三级权限体系。在 Linux 里每个文件都记着三组权限属主owner权限、属组group权限、其他用户others权限。每组权限又分读r4、写w2、执行x1三种数字表示法是它们的和。比如755表示属主可读写执行7421属组可读可执行541其他人可读可执行541。这套设计相比 Windows 的 ACL 权限要简单直接得多但同时它也意味着你必须理解文件属主和进程运行用户的关系否则容易出现权限混乱。我举个真实场景在服务器上部署一个 Web 应用Nginx 进程以www-data用户运行站点目录属主如果被设成root:root权限是755那 Web 进程能读文件但不能写。如果应用需要上传文件你只改文件权限改成777当时能写但这是非常危险的做法因为任何本地用户都能改了。正确做法是把目录属主改成www-data或者把www-data加进目录属组然后给属组加写权限。这里我建议你养成一个习惯拿到任何一个 Linux 系统第一件事就是用id命令看当前用户和组信息用ls -l看关键目录的属主属组。理解了这套权限模型后面配 SSH、配 Web、搞共享目录都会顺很多。2.2 用户管理常用操作useradd、usermod、passwd创建用户是 day02 必须练熟的操作。推荐用useradd加参数的方式而不是直接改/etc/passwd虽然直接改文件在某些紧急场景下也能用但容易出错。# 创建用户同时指定 home 目录、登录 shell、附加组 useradd -m -d /home/zhangsan -s /bin/bash -G wheel zhangsan # -m自动创建 home 目录 # -d指定 home 目录路径 # -s指定登录 shell # -G附加组可以多个逗号分隔 # 设置或修改密码 passwd zhangsan # 查看用户信息 id zhangsan这里有个细节如果你不加-m很多发行版默认不会自动创建 home 目录用户登录后进到一个不存在的目录会出现各种路径问题。另外-G wheel是为了让用户加入管理员组具体组名看发行版CentOS/RHEL 系是wheelUbuntu/Debian 系是sudo。删除用户用userdel -r zhangsan-r会连 home 目录和邮件池一起删不加-r则只删用户但保留文件。你要是有强迫症删完用户记得检查一下/etc/passwd、/etc/group、/etc/shadow三个文件里有没有残留条目避免 uid 复用导致权限串号。2.3 chmod、chown、chgrp 的实操细节权限修改三兄弟chmod改权限位chown改属主chgrp改属组。这仨命令看起来简单但实际使用中有几个坑我踩过好几次。第一个坑chown后面是先写属主再写属组中间用冒号分隔比如chown root:root file。很多新手容易把顺序搞反写成chown root:root还好如果要只改属组得写chown :group file注意前面的冒号不能省省了就会把group当成用户名去解析直接报错。第二个坑递归授权要谨慎。chmod -R 777 /some/dir这种命令我强烈建议少用。一旦你递归改了系统目录比如/usr或/var那系统基本就半残了——某些程序启动时会因为关键文件权限过宽而拒绝运行更糟的是给恶意程序开了后门。正确做法是分级授权比如网站目录下目录用755普通文件用644需要写入的上传目录单独设775属组可写。第三个坑chmod除了数字法还有符号法。比如chmod ux file表示给属主加执行权限chmod g-w,o-r file表示属组去写、其他去读。符号法在微调权限时比数字法直观但很多教程不讲导致新手只会777。实际排障时符号法非常有用比如一键给所有 shell 脚本加执行权限find /path/to/scripts -name *.sh -exec chmod x {} \;2.4 用 ACL 补足基础权限的短板基础权限模型的短板在于一个文件只能有一个属主和一个属组。但实际场景里经常出现“A、B 两个不同组的人都要能读写某个共享目录”的需求这时候基础权限解决不了得用 ACLAccess Control List。ACL 可以给特定用户或组单独设置权限而不受传统属主/属组限制。查看 ACL 用getfacl设置用setfacl# 给 lisi 用户针对 /data/share 目录增加读写执行权限 setfacl -m u:lisi:rwx /data/share # 删除某个用户的 ACL 条目 setfacl -x u:lisi /data/share # 递归设置目录及目录下已有文件的 ACL setfacl -Rm u:lisi:rwx /data/share注意递归-R只对已有文件生效如果以后在目录里新建了文件默认不会继承 ACL。要让新文件自动继承需要设置默认 ACLsetfacl -m d:u:lisi:rwx /data/share这个d:前缀就是 default 的意思设置之后这个目录下新建的文件会自动赋予 lisi 读写执行权限。这个技巧在做团队共享目录、FTP 目录、Samba 共享时非常实用。3. 进程管理与后台任务别再用 CtrlC 硬扛所有进程3.1 ps、top、htop 的合适使用场景进程管理是运维的核心功不会看进程状态排查问题几乎寸步难行。ps是静态快照适合“看一眼当前有哪些进程”。最常用的组合是ps -ef和ps aux两者展示的信息略有差别但基本都包含 PID进程号、PPID父进程号、CPU%、内存%、启动命令。如果你想找某个特定进程配合grep是最快的方式ps -ef | grep nginx这里有个小技巧用grep -v grep把 grep 自身那行过滤掉或者直接用pgrep -af nginxpgrep 命令就是专门干这个的更干净。pgrep -f是按完整命令行匹配而不是只匹配进程名在找脚本进程时特别管用。top是动态刷新适合“持续观察哪几个进程吃 CPU、吃内存”。进去之后按P按 CPU 排序按M按内存排序按q退出。如果你在排查内存泄漏top 的RES列常驻内存比VIRT列更有参考价值VIRT 只是虚拟内存不代表真实占用。htop是 top 的增强版支持鼠标操作、树状视图、直接 F9 杀进程但很多最小化安装的服务器没有需要自己装。我的建议是top 必须熟练htop 能装就装毕竟排障时一个高亮彩色界面比满屏黑字舒服得多。3.2 后台运行、nohup、setsid、tmux 一次讲清新手最常见的困惑是明明程序在终端里跑得好好的一关终端窗口程序就死了这是为什么因为大多数程序是终端的前台进程终端关闭时内核会向会话中的进程发送 SIGHUP 信号进程没处理这个信号默认行为就是终止。解决办法就是让进程脱离终端会话。最简单的是在命令末尾加让它在后台运行。但这只解决了“不占你终端”的问题终端关闭时它依然可能被杀因为它的会话还是和终端关联。更可靠的是nohupnohup python3 myscript.py /var/log/myscript.log 21 拆解一下nohup让进程忽略 SIGHUP logfile把标准输出重定向到文件21把标准错误也并到标准输出里最后的让命令在后台运行。这个命令组合是运维日常最常用的启动姿势没有之一。setsid更彻底它让进程直接成为新的会话首进程完全脱离终端控制。用法更简单setsid python3 myscript.py myscript.log 21连都不用加因为它已经是独立的会话了。但说实话日常场景里nohup已经够用setsid我一般只在写服务启动脚本时用。如果你需要更高级的会话管理比如关掉终端后过几小时再回来查看程序输出、在远程跑长任务、同事之间共享一个操作会话那就该上tmux了。tmux 是终端复用器的王者最核心的概念是“会话session”和“窗口window”tmux new -s work # 新建一个名为 work 的会话 tmux detach # 从会话中分离相当于挂起快捷键 Ctrlb d tmux ls # 查看所有会话 tmux attach -t work # 重新连接 work 会话在 tmux 里跑任务就算你 SSH 断开任务照常运行。回来tmux attach就能看到现场这一点在跑长任务、部署脚本、数据库迁移时真的救命。3.3 kill、killall、pkill杀进程的高阶姿势杀进程不是上来就kill -9。很多新手的习惯是卡住了就kill -9结果不仅没解决问题还可能把数据弄丢。这里必须理解 Linux 信号机制。kill默认发送 SIGTERM15这是“请优雅退出”程序收到后会清理资源、保存状态、然后退出。kill -9发送 SIGKILL这是“立刻终止不容商量”内核直接回收资源但程序没机会做任何清理可能造成文件损坏、数据不一致。正确流程是先kill -15 PID等几秒看进程是否还在不行再kill -9 PID。当然对于僵尸进程Z 状态kill 是无效的你只能杀它的父进程让 init 去回收。killall nginx按进程名杀pkill -f python.*server.py按完整命令行匹配杀这两者比逐个查 PID 要快得多。但有个大坑pkill -f太容易被自己误伤——比如你用pkill -f grep可能会把pgrep或者pkill自己匹配进去。更安全的做法是先用pgrep -af看一下匹配到了哪些进程确认没问题再杀。3.4 系统服务管理systemctl 的日常用法现在的主流发行版都用 systemd 管理服务service和chkconfig在老系统上还能见到但新环境基本是systemctl的天下。day02 至少掌握这几个systemctl start nginx # 启动服务 systemctl stop nginx # 停止服务 systemctl restart nginx # 重启服务 systemctl status nginx # 查看服务状态包括 PID、最近日志、活跃状态 systemctl enable nginx # 设置开机自启 systemctl disable nginx # 取消开机自启 systemctl list-units --typeservice --staterunning # 列出所有运行中的服务systemctl status输出的信息量很大包括服务当前状态active/exited/failed、主进程 PID、最近几条日志。排障时先跑这个基本能确定服务是被杀掉了、启动失败还是压根没启动。还有个隐藏技巧systemctl status是有退出码的。进程正常运行返回 0异常返回非 0在脚本里可以用$?判断服务是否健康。比如systemctl status nginx /dev/null 21 if [ $? -ne 0 ]; then systemctl restart nginx fi这就在 shell 脚本里实现了一个极简的保活逻辑。4. 文本处理三剑客grep、sed、awk 的实战组合4.1 grep不只是简单的关键词搜索grep 是 Linux 上使用频率最高的命令之一但很多人只会grep keyword file这种简单用法。稍微深入一点grep 能做的事情远超你想象。首先grep -r可以递归搜索目录排错日志时特别常用。grep -i忽略大小写grep -n显示行号grep -v反选排除匹配行。组合起来就是grep -rn ERROR /var/log/app/ | grep -v healthcheck其次grep -A和grep -B可以在匹配行之后/之前显示指定行数的上下文看异常日志时非常实用。比如查看报错前后各 5 行grep -A 5 -B 5 OutOfMemoryError /var/log/app.log还有grep -E支持扩展正则grep -P支持 Perl 兼容正则。比如查找所有 IP 地址一条命令搞定grep -P -o \d{1,3}(\.\d{1,3}){3} access.log | sort | uniq -c | sort -rn这条命令还能顺带统计每个 IP 出现的次数排在前面的就是访问最频繁的用来识别异常扫描很有用。4.2 sed流编辑器增删改查一把梭sed 的核心用法是“流式处理”它逐行读取文件对每一行执行替换、删除、插入操作默认不修改原始文件除非加-i。最常用的替换操作# 把文件里所有 old 替换成 new预览到屏幕不写文件 sed s/old/new/g file.txt # 直接修改文件注意 -i 会覆盖原文件建议先备份 sed -i s/old/new/g file.txt # 只替换每行第 2 次出现的内容 sed s/old/new/2 file.txt-i后面可以跟备份后缀比如sed -i.bak s/old/new/g file.txt会自动生成一个file.txt.bak备份文件再改原文件。改系统配置前我强烈建议养成这个习惯改坏了还能秒回滚。sed 也可以按行号操作sed -n 5,10p file.txt # 查看第 5 到 10 行 sed /ERROR/d file.txt # 删除所有包含 ERROR 的行-n和p的组合就是“只打印匹配的行”相当于一个更精确的 grep。把所有 Nginx 配置里被注释掉的 server_name 行摘出来只用一个命令sed -n s/^#\s*server_name\s*//p nginx.conf4.3 awk按列处理的王牌工具awk 是按列处理文本的神器尤其适合处理日志、表格数据。它的核心思想是把每一行按分隔符拆成多个字段然后对字段做处理。默认分隔符是空格可以用-F指定。最经典的用法是打印指定列# 打印 df 输出中的第 1 列文件系统和第 5 列使用率 df -h | awk {print $1, $5}再进阶一点awk 可以做条件判断和统计# 找出磁盘使用率超过 80% 的分区 df -h | awk NR1 $5 80 {print $1, $5} # 统计日志中 500 错误的数量 awk $9 500 {count} END {print count} access.logawk 最大的价值在于它本身就是一门小语言有变量、循环、数组。比如统计访问量 Top 10 的 URLawk {count[$7]} END {for (url in count) print count[url], url} access.log | sort -rn | head -10这条命令的意思对每一行用第 7 列URL做 key给对应的计数器加 1。文件处理完后遍历所有 URL 打印计数再用sort -rn倒序排序取前 10。这放在任何日志分析工具里都是核心逻辑。4.4 组合实战从日志里快速定位故障现场三个工具单独用都简单组合起来才见功力。举个例子假设你是 Java 应用运维应用日志打印格式是2025-01-15 10:22:33 ERROR - NullPointerException你要统计当天每个小时出现 ERROR 的次数然后找出次数最多的那一个小时出现在哪些行。第一步用 awk 提取小时字段并按小时分组统计awk {hoursubstr($2,1,2); if ($3ERROR) count[hour]} END {for (h in count) print h, count[h]} app.log | sort -k2 -rn第二步找到最多的小时假设是14再筛出那一小时内所有 ERROR 的完整日志grep 14: app.log | grep ERROR第三步如果信息还不够用 sed 把错误前后的上下文捞出来grep -n NullPointerException app.log | head -5 | awk -F: {print $1} | xargs -I{} sed -n {},{}p app.log这三板斧打完问题基本就能定位到具体代码行或者具体输入参数了。这套组合拳在没有任何日志分析平台的裸环境下就是我处理问题的主要手段。5. 系统状态与资源查看知己知彼百战不殆5.1 df、du 与磁盘占用排查磁盘满是最常见的故障之一也是最容易排查的。df -h看文件系统整体使用率du -sh看目录总共多大du -h --max-depth1看一层目录的大小分布。排查“/ 分区红了但不知道什么占的空间”的标准流程df -h # / 分区 100% 满 cd / du -h --max-depth1 | sort -rh | head -10 # 找到 /var 占最大 cd /var du -h --max-depth1 | sort -rh | head -10 # 再往下钻到 /var/log找到几个巨型日志文件这个过程就像剥洋葱一层层找到最大的目录最后一层定位到大文件。我经常遇到的情况是某个进程持续输出日志日志文件不断增长几分钟就把磁盘写满。这时候除了删日志更重要的是搞清楚为什么日志会爆发式增长——多半是应用进入了死循环或者报错刷屏。还有个隐藏技巧用lsof | grep deleted找出“已被删除但仍有进程占用”的文件。这种文件不占目录空间但占磁盘空间。如果删了文件磁盘空间没释放大概率就是这个原因。比如网站上传的临时图片被删除后如果 Nginx 进程还在写这个句柄文件占的空间就一直在。用lsof找到 PID 再重启那个进程空间才会真正释放。5.2 free、vmstat、iostat 读懂内存与 IOfree -h看内存使用。很多新手看到free里 avail 值小就急着加内存其实这是误区。Linux 的内存策略是“能用就用”——内存空闲着也是浪费不如拿去缓存磁盘块。所以看内存压力不能只看 free 列要看available列真实可用的内存以及swap的使用情况。如果 swap 持续增长说明物理内存真的不够了。排查到底谁在吃内存用top按内存排序或者用ps快照ps aux --sort-%mem | head -10vmstat更适合看整体趋势。vmstat 1每秒刷新一次重点关注r运行队列、b阻塞进程数、si/so换入换出这几列。如果r长期大于 CPU 核数说明 CPU 过载如果si/so常年不为 0说明内存压力很大系统正在频繁换页这时候加内存比调优来得更实在。iostat看磁盘 IO重点看%util和await。%util接近 100% 说明磁盘已成为瓶颈await过长说明 IO 响应慢。遇到数据库慢查询排查时iostat 能帮你判断是 SQL 的问题还是磁盘硬件的问题。5.3 系统时间与时区管理时间同步是运维里一个看似简单、坑却很多的点。如果服务器时间和真实时间差了太多会导致日志时间错乱、HTTPS 证书校验失败、数据库主从同步异常等一系列问题。查看时间date # 系统时间 date -R # 带时区显示比如 0800 timedatectl # 查看系统时间、时区、NTP 同步状态修改时区timedatectl set-timezone Asia/ShanghaiNTP 同步# 手动同步一次 ntpdate -u ntp.aliyun.com # 老工具很多新系统已移除 # 推荐用 chrony systemctl restart chronyd chronyc sources -v # 查看 NTP 同步状态如果发现服务器时间一直不准优先检查 chronyd 或 ntpd 是否运行、是否能连通 NTP 服务器。防火墙挡了 UDP 123 端口是一个常见原因。5.4 网络查看与连接排查网络排查在 day02 先掌握最基础的工具组合。ip addr看网卡 IPip route看路由ping看连通性。如果要监听的端口被占了用ss或旧的netstatss -tlnp # 查看所有监听的 TCP 端口及对应进程 ss -antp # 查看所有 TCP 连接状态排查“端口起不来”的标准姿势ss -tlnp | grep :8080 # 8080 是否已被别的进程占用如果是服务器的端口明明通了但外部访问不了那大概率是防火墙问题。用firewall-cmd --list-all或ufw status看规则再决定放行还是关掉。这些都是排障最基础的工具但要真正用好得学会看输出的每一列代表什么。比如ss -antp输出里有LISTEN、ESTAB、TIME_WAIT等状态TIME_WAIT大量堆积说明连接关闭频繁多半是短连接过多这时候调应用的连接池比关防火墙更有效。6. 环境变量与 Shell 脚本入门让命令自动化起来6.1 环境变量到底是怎么生效的环境变量是 Shell 和程序之间传递配置信息的通道。echo $PATH能看当前 PATHexport PATH$PATH:/new/path能临时追加。但这里有个新手容易混乱的点export只对当前 Shell 会话有效关闭终端就没了。要让环境变量永久生效需要写进配置文件。不同发行版、不同 Shell 的配置加载顺序不一样是新手很容易懵的地方。以 bash 为例登录 shell 会依次加载/etc/profile、~/.bash_profile或~/.bash_login、~/.profile非登录交互 shell 则加载~/.bashrc。CentOS 上通常会在~/.bash_profile里手动 source~/.bashrc而 Ubuntu 则是/etc/profile里 source/etc/bash.bashrc。我个人的建议是把自定义 PATH 和别名写到~/.bashrc底部因为非登录 shell比如在 tmux 里新开窗口也会加载它。写完后执行source ~/.bashrc立即生效不用重新登录。像 Anaconda 的环境变量装完之后提示你写进~/.bashrc就是这么个道理。6.2 自定义 PATH 与 JAVA_HOME 这类典型配置在命令行里执行java -version时Shell 其实是在 PATH 里找名为 java 的可执行文件。如果你装了 JDK 但没配 PATHShell 就找不到直接报command not found。典型配置方式是在~/.bashrc里export JAVA_HOME/opt/jdk17 export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOME/lib注意 PATH 的赋值顺序$JAVA_HOME/bin放在最前面意思就是优先使用我们自己装的 JDK而不是系统自带的 OpenJDK。这个“越靠前越优先”的规则在排查“明明装了新版本但命令还是老版本”的问题时是关键。检查是否生效which java java -version echo $PATH6.3 第一个实用脚本日志清理脚本环境变量和命令掌握后写一个简单的日志清理脚本是把知识串起来的最佳练习。我随便写一个监控并清理超过 N 天日志的脚本#!/bin/bash # 清理超过 7 天的日志文件 # 先打印将被删除的文件人工确认后再取消注释执行删除 LOG_DIR/var/log/myapp DAYS7 find $LOG_DIR -name *.log -type f -mtime $DAYS -print # find $LOG_DIR -name *.log -type f -mtime $DAYS -delete这个脚本有几个值得说的点。-mtime 7表示修改时间在 7 天之前的文件-type f限定只找普通文件避免误删目录。先打印再删是我强烈建议的保险策略生产环境直接删文件的脚本一定要先验证一遍输出结果。更稳健的脚本会考虑磁盘占用率作为触发条件#!/bin/bash LOG_DIR/var/log/myapp THRESHOLD80 usage$(df -h $LOG_DIR | awk NR2 {print $5}) if [ $usage -gt $THRESHOLD ]; then find $LOG_DIR -name *.log -type f -mtime 3 -delete echo 磁盘使用率 ${usage}%已清理 3 天前的日志。 else echo 磁盘使用率 ${usage}%无需清理。 fidf -h输出的第五列是使用率百分比awk$5把它转成数字参与比较。这个脚本加进 crontab 里每天执行一次就能实现日志自动轮转算是最简单的运维自动化实践。6.4 crontab 调度任务入门cron 是 Linux 自带的定时任务工具crontab -e编辑当前用户的定时任务。格式是五个字段分、时、日、月、周。举个例子# 每天凌晨 2 点执行备份脚本 0 2 * * * /home/user/bin/backup.sh # 每 5 分钟检查一次服务状态 */5 * * * * /home/user/bin/check_service.sh # 每周一早上 8 点清理临时目录 0 8 * * 1 /usr/bin/find /tmp -type f -mtime 7 -delete配置好之后日志会写到/var/log/cron或通过journalctl -u crond查看。如果定时任务没有执行先排查 crond 服务是否在跑再看脚本有没有执行权限、有没有写执行日志。这里提醒一个常见的坑cron 执行环境和我们手动登录终端的环境不一样它没有加载~/.bashrc所以脚本里如果用到了自定义 PATH 或者 JAVA_HOME必须在脚本开头显式设置否则就会出现“手动执行脚本没问题但 cron 里跑就报 command not found”的诡异现象。7. 常见故障排查实录这些问题我踩过你们别再踩了7.1 故障案例 1磁盘空间满了但是删了文件还没释放现象df -h显示/分区使用率 100%但du -sh /算下来远没到那么大。于是你以为自己算错了但实际是文件系统上有文件被删除了但还有进程持有它的文件句柄。排查流程df -h du -sh /* # 找不到大头 lsof | grep deleted # 发现 /var/log/nginx/access.log (deleted) 还被 nginx 进程占用 systemctl restart nginx df -h # 空间释放了这类问题最常见的场景就是日志文件你rm了日志但写入日志的进程还在运行这个文件的实际数据块一直没释放。记住删除文件不等于释放磁盘还要确保没有进程继续持有该文件的句柄。7.2 故障案例 2程序一关终端就“消失”现象在远程 SSH 终端里启动了一个 Java 程序一切正常。退出 SSH 再重连发现进程没了日志里也没有明显报错。原因就是终端关闭后 SIGHUP 把进程带走了。解决办法就是用前面讲的nohup或setsid。更规范的做法是写成 systemd service让 systemd 管理进程生命周期这样不仅能开机自启还能崩溃自动重启[Unit] DescriptionMy Java App Afternetwork.target [Service] Typesimple Userappuser ExecStart/usr/bin/java -jar /opt/app/myapp.jar Restarton-failure RestartSec5 EnvironmentJAVA_HOME/opt/jdk17 [Install] WantedBymulti-user.target把文件放到/etc/systemd/system/myapp.service然后systemctl daemon-reload systemctl enable --now myapp7.3 故障案例 3明明有权限但脚本执行报 Permission denied现象写了个deploy.shls -l看权限也正常但执行./deploy.sh就报Permission denied。这个问题的原因多半是脚本没有执行权限。解决chmod x deploy.sh ./deploy.sh另一个变种是“执行到一半报 Permission denied”那是脚本内部某个命令的执行权限不足或者脚本尝试往没有写权限的目录写入文件。排查方式是把脚本一行行拆开执行或者用bash -x deploy.sh开启调试模式它会一条条打印执行的命令和结果很容易定位是哪一步出错。7.4 故障案例 4端口被占用服务起不来现象启动 Nginx 报错bind() to 0.0.0.0:80 failed (98: Address already in use)。排查流程ss -tlnp | grep :80 # 看到 PID 后确认是哪个进程占着 80 端口 ps -p PID -o pid,comm,args # 如果是旧版 nginx 没杀干净 kill -15 PID # 还不退就 kill -9 systemctl start nginx这里给一个容易踩坑的经验如果端口上跑的是一个重要的线上服务杀之前一定要确认清楚。有一次我遇到过 80 端口被一个异常启动的 Java 测试进程占了杀完之后发现那竟然是另一个部门在用的内部服务搞得大家虚惊一场。现在我的习惯是杀进程前一定先ps -p看启动命令、看启动时间确认是预期内的进程才动手。7.5 故障排查速查表对照这表能解决八成日常问题现象可能原因排查命令解決思路命令找不到PATH 没配或软件没装echo $PATH,which cmd重装或用绝对路径执行磁盘满日志爆炸或大文件残留df -h,du -sh /*, lsofgrep deleted内存不足应用泄漏或缓存太多free -h,top -o %MEM,ps aux --sort-%mem重启应用或加内存端口被占用进程残留或冲突ss -tlnp确认进程后 kill或用其它端口服务起不来配置错误或依赖缺失systemctl status -l,journalctl -u 服务名 -e看日志定位修复配置关终端进程就没了未脱离终端会话检查父进程nohup启动用 nohup / systemd 管理文件删了空间没释放有进程持有句柄lsofgrep deleted时间不准NTP 失效或时区错误timedatectl,chronyc sources设置时区重启 chronydcron 任务不执行环境变量缺失或服务没启动journalctl -u crond,crontab -l脚本内显式设置 PATH网络不通防火墙或路由问题ping,ip route,firewall-cmd --list-all按链路逐层排查8. 学习建议与扩展路径day02 的内容量其实不小从用户权限到进程管理从文本处理到故障排查每块都能展开成一篇独立的文章。我在实际学习时的一个体会是不要追求“把所有命令背下来”而是要追求“遇到问题能想到用什么工具”。命令是工具场景化学习比死记硬背高效得多。一个比较有效的方法是在虚拟机里故意制造故障然后自己排查。比如把 nginx 的端口改成 90然后启动看报错比如故意删掉一个系统日志文件然后观察磁盘占用比如写一个不断往内存写数据的 Python 脚本然后用top观察系统怎么崩。这些“搞破坏”的练习才是真正把知识变成能力的过程。这套笔记之后可以往几个方向扩展一是 Shell 脚本编程深入把循环、函数、判断都用熟写出一套完整的自动化脚本二是服务部署实战比如用 systemd 管理 Nginx、MySQL、Java 应用搞明白服务开机自启的完整链路三是网络进阶把 tcpdump、iptables、路由策略这些搞明白能独立排查跨服务器通信的问题。每个方向都能让 day02 这些基础发挥出指数级的价值。最后说一个我个人的建议日常工作中遇到不认识的命令先用man查手册再看/usr/share/doc里的示例最后再上网搜。搜索引擎能解决 80% 的问题但这 80% 里有一半是英文资料所以英文阅读能力对 Linux 学习来说是越早开始练习越好的投资。