Ubuntu 命令行实战指南

这不是一本教科书式的命令手册,而是一份面向真实场景的实战指南。当你需要部署一个服务、排查一个问题、管理一台服务器时,你会在这里找到答案。

Ubuntu 命令行实战指南
Photo by Gabriel Heinzer / Unsplash

一、命令行效率神器

1.1 历史命令快速搜索

Ctrl+R 就是其中之一:

# Ctrl+R: 反向搜索历史命令
# 输入关键词,自动匹配你用过的命令
# 再按 Ctrl+R 继续向前搜索
# Enter 执行,Ctrl+C 取消

# 查看所有历史
history

# 执行历史中的第123条命令
!123

# 执行上一条命令
!!

# 执行最近一条以 docker 开头的命令
!docker

1.2 其他效率技巧

# Ctrl+A: 跳到行首
# Ctrl+E: 跳到行末
# Ctrl+U: 删除光标前的所有内容
# Ctrl+K: 删除光标后的所有内容
# Ctrl+W: 删除光标前的一个单词
# Ctrl+L: 清屏(等同于 clear)

# Alt+.: 粘贴上一条命令的最后一个参数
# 场景: 你刚 ls /var/log/nginx/,现在想 cd 过去
cd Alt+.  # 自动补全为 cd /var/log/nginx/

二、服务管理实战

2.1 场景:部署一个 Nginx 服务

第一步:安装

sudo apt update
sudo apt install nginx

第二步:检查服务状态

# 查看服务状态(最常用)
sudo systemctl status nginx

# 查看是否正在运行
sudo systemctl is-active nginx

# 查看是否开机自启
sudo systemctl is-enabled nginx

第三步:管理服务

# 启动服务
sudo systemctl start nginx

# 停止服务
sudo systemctl stop nginx

# 重启服务(配置改了后用这个)
sudo systemctl restart nginx

# 重新加载配置(不中断服务,推荐)
sudo systemctl reload nginx

# 设置开机自启
sudo systemctl enable nginx

# 取消开机自启
sudo systemctl disable nginx

# 一步到位:启用并立即启动
sudo systemctl enable --now nginx

2.2 场景:创建自己的服务

假设你写了一个 Python 程序 /home/user/myapp/app.py,想让它作为服务运行:

创建服务文件

sudo nano /etc/systemd/system/myapp.service

服务文件内容

[Unit]
Description=My Python Application
After=network.target

[Service]
Type=simple
User=user
WorkingDirectory=/home/user/myapp
ExecStart=/usr/bin/python3 /home/user/myapp/app.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

关键配置说明

  • After=network.target: 网络就绪后再启动
  • Type=simple: 最常用的类型,程序前台运行
  • Restart=always: 挂了自动重启
  • RestartSec=10: 重启前等待 10 秒
  • WantedBy=multi-user.target: 开机自启

启用服务

# 重新加载 systemd 配置
sudo systemctl daemon-reload

# 启动并设置自启
sudo systemctl enable --now myapp

# 查看状态
sudo systemctl status myapp

2.3 场景:找出占用端口的进程

使用 lsof(最常用)

# 查看 8080 端口被谁占用
sudo lsof -i :8080

# 输出示例:
# COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
# nginx    1234 root    6u  IPv4  12345      0t0  TCP *:8080 (LISTEN)

# 只显示 PID
sudo lsof -ti :8080

# 查看某个进程打开了哪些文件
sudo lsof -p 1234

# 查看某个用户打开的所有文件
sudo lsof -u username

# 查看某个目录下被打开的文件
sudo lsof +D /var/log

# 查看某个文件被哪些进程打开
sudo lsof /var/log/nginx/access.log

# 查看所有网络连接
sudo lsof -i

# 查看 TCP 连接
sudo lsof -i tcp

# 查看 UDP 连接
sudo lsof -i udp

# 查看某个 IP 的连接
sudo lsof -i @192.168.1.1

# 持续监控某个端口(每 2 秒刷新)
watch -n 2 'sudo lsof -i :8080'

使用 netstat

# 查看所有监听的端口
sudo netstat -tlnp
# -t: TCP
# -l: 监听中的
# -n: 显示数字地址
# -p: 显示进程信息

# 查看所有连接(包括已建立的)
sudo netstat -anp

# 查看 8080 端口
sudo netstat -tlnp | grep 8080

# 统计各状态的连接数
netstat -an | awk '/^tcp/ {print $6}' | sort | uniq -c

使用 ss(更现代,推荐)

# 查看所有监听的 TCP 端口
sudo ss -tlnp

# 查看 8080 端口
sudo ss -tlnp | grep 8080

# 查看所有已建立的连接
sudo ss -tnp

# 查看连接统计
ss -s

# 查看某个进程的网络连接
sudo ss -tp | grep nginx

一步杀掉占用端口的进程

# 找到 PID 并杀掉
sudo kill $(sudo lsof -ti :8080)

# 强制杀掉
sudo kill -9 $(sudo lsof -ti :8080)

# 或者用 fuser
sudo fuser -k 8080/tcp

2.4 场景:查看服务的实时日志

systemd 服务日志(推荐)

# 查看服务日志(最近的)
sudo journalctl -u nginx

# 实时滚动查看(最常用)
sudo journalctl -u nginx -f

# 查看最近 100 行
sudo journalctl -u nginx -n 100

# 从最后开始看,并实时更新
sudo journalctl -u nginx -f -n 50

# 查看今天的日志
sudo journalctl -u nginx --since today

# 查看最近 1 小时
sudo journalctl -u nginx --since "1 hour ago"

# 查看某个时间段
sudo journalctl -u nginx --since "2024-10-20 10:00" --until "2024-10-20 11:00"

# 显示详细信息(包括完整输出)
sudo journalctl -u nginx -o verbose

# 只看错误级别的日志
sudo journalctl -u nginx -p err

# 查看多个服务的日志
sudo journalctl -u nginx -u mysql

查看应用自己的日志文件

# 实时查看日志末尾(最常用)
tail -f /var/log/nginx/access.log

# 查看最后 50 行
tail -n 50 /var/log/nginx/error.log

# 查看前 20 行
head -n 20 /var/log/nginx/access.log

# 实时查看多个日志
tail -f /var/log/nginx/access.log /var/log/nginx/error.log

# 分页查看日志(可上下翻页)
less /var/log/nginx/access.log
# 空格:下一页
# b:上一页
# /:搜索
# q:退出

查看 nohup 后台进程的日志

# 如果用了 nohup python3 app.py > app.log 2>&1 &
tail -f app.log

# 如果没指定输出文件,默认在 nohup.out
tail -f nohup.out

2.5 场景:在日志中查找特定内容

使用 grep 搜索日志

# 在日志中搜索包含 "error" 的行
grep "error" /var/log/nginx/error.log

# 忽略大小写
grep -i "error" /var/log/nginx/error.log

# 显示行号
grep -n "error" /var/log/nginx/error.log

# 显示匹配行的前后 3 行(看上下文)
grep -C 3 "error" /var/log/nginx/error.log

# 只显示前 5 行
grep -B 5 "error" /var/log/nginx/error.log

# 只显示后 5 行
grep -A 5 "error" /var/log/nginx/error.log

# 统计匹配次数
grep -c "error" /var/log/nginx/error.log

# 显示不包含某个词的行(反向搜索)
grep -v "debug" /var/log/app.log

# 使用正则表达式
grep -E "error|warning|critical" /var/log/nginx/error.log

# 递归搜索目录下所有文件
grep -r "error" /var/log/nginx/

# 只显示文件名,不显示内容
grep -l "error" /var/log/nginx/*

实时搜索日志

# 实时查看包含 "error" 的日志
tail -f /var/log/nginx/error.log | grep "error"

# 高亮显示匹配的内容
tail -f /var/log/nginx/error.log | grep --color "error"

# 实时查看 systemd 日志中的错误
sudo journalctl -u nginx -f | grep -i error

组合过滤(管道操作)

# 查找包含 "error" 但不包含 "debug" 的行
grep "error" /var/log/app.log | grep -v "debug"

# 统计每个 IP 的访问次数
cat /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn

# 查找状态码为 500 的请求
grep " 500 " /var/log/nginx/access.log

# 查看最近 1 小时的错误,并统计数量
sudo journalctl -u nginx --since "1 hour ago" | grep -i error | wc -l

使用 awk 提取特定字段

# 提取 Nginx access.log 中的 IP 地址(第一列)
awk '{print $1}' /var/log/nginx/access.log

# 提取请求的 URL(第七列)
awk '{print $7}' /var/log/nginx/access.log

# 提取状态码(第九列)
awk '{print $9}' /var/log/nginx/access.log

# 条件过滤:只显示状态码为 500 的行
awk '$9 == 500' /var/log/nginx/access.log

# 统计各个状态码的数量
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

使用 sed 过滤时间范围

# 查看某个时间段的日志
sed -n '/2024-10-21 10:00/,/2024-10-21 11:00/p' /var/log/app.log

# 删除包含某个词的行后再查看
sed '/debug/d' /var/log/app.log

三、文件编辑与配置

3.1 文本编辑器选择

# nano: 最简单,适合新手
nano filename.txt
# Ctrl+O 保存, Ctrl+X 退出

# vim: 功能强大,有学习曲线
vim filename.txt
# 按 i 进入编辑模式
# 按 Esc 退出编辑模式
# 输入 :wq 保存并退出
# 输入 :q! 不保存退出

# 如果只是查看文件
cat filename.txt
less filename.txt  # 可以翻页,q 退出

3.2 场景:编辑 Nginx 配置

# 编辑主配置
sudo nano /etc/nginx/nginx.conf

# 编辑站点配置
sudo nano /etc/nginx/sites-available/default

# 测试配置是否有语法错误(重要!)
sudo nginx -t

# 配置正确后重新加载
sudo systemctl reload nginx

3.3 场景:修改环境变量

# 临时修改(关闭终端就失效)
export PATH=$PATH:/opt/myapp/bin

# 永久修改(当前用户)
nano ~/.bashrc
# 在文件末尾添加:
# export PATH=$PATH:/opt/myapp/bin

# 使配置生效
source ~/.bashrc

# 或者重新登录

四、文件与目录操作

4.1 查找文件

# 按名称查找
find /var/log -name "*.log"

# 查找最近 7 天修改的文件
find /var/log -mtime -7

# 查找大于 100M 的文件
find /var/log -size +100M

# 在文件内容中搜索(递归搜索目录)
grep -r "error" /var/log/nginx/

# 忽略大小写
grep -ri "error" /var/log/nginx/

# 显示行号
grep -rn "error" /var/log/nginx/

4.2 磁盘空间管理

# 查看磁盘使用情况
df -h

# 查看当前目录下各子目录的大小
du -h --max-depth=1

# 找出最大的 10 个文件
du -ah /var/log | sort -rh | head -10

# 查看某个目录的总大小
du -sh /var/log/nginx/

4.3 文件权限与所有者

# 查看详细信息
ls -lh

# 修改所有者
sudo chown user:group filename

# 递归修改目录
sudo chown -R user:group /var/www/html

# 修改权限(755: 所有者全权限,其他人读+执行)
chmod 755 script.sh

# 让脚本可执行
chmod +x script.sh

# 常用权限:
# 644: 文件(所有者读写,其他人只读)
# 755: 目录或可执行文件
# 600: 私密文件(如 SSH 密钥)

五、进程管理

5.1 查看进程

# 查看所有进程
ps aux

# 查看特定进程(比如 nginx)
ps aux | grep nginx

# 实时查看进程(类似 Windows 任务管理器)
top
# 或更友好的
htop  # 需要先安装: sudo apt install htop

# 按内存排序查看前 10 个进程
ps aux --sort=-%mem | head -10

# 按 CPU 排序
ps aux --sort=-%cpu | head -10

5.2 后台运行与进程管理

场景:需要运行一个长期任务,退出 SSH 后还要继续运行

# 方法一:使用 nohup(最常用)
nohup python3 app.py > app.log 2>&1 &
# nohup: 忽略挂断信号
# > app.log: 标准输出重定向到文件
# 2>&1: 错误输出也重定向到同一文件
# &: 后台运行

# 查看 nohup 进程输出
tail -f app.log

# 方法二:使用 screen(可以随时重新连接)
screen -S myapp
python3 app.py
# 按 Ctrl+A 然后按 D 断开(进程继续运行)

# 重新连接到 screen
screen -r myapp

# 查看所有 screen 会话
screen -ls

# 方法三:使用 tmux(更现代的 screen)
tmux new -s myapp
python3 app.py
# 按 Ctrl+B 然后按 D 断开

# 重新连接
tmux attach -t myapp

# 查看 tmux 会话
tmux ls

查看后台任务

# 查看当前终端的后台任务
jobs

# 查看后台任务的 PID
jobs -l

# 把后台任务调到前台
fg %1  # 1 是任务编号

# 把前台任务暂停并放到后台
Ctrl+Z  # 先暂停
bg      # 再后台运行

# 杀掉后台任务
kill %1

六、网络调试与诊断

6.1 测试连接

# 测试网络连通性
ping google.com
ping -c 4 google.com  # 只 ping 4 次

# 测试端口是否开放
telnet example.com 80

# 或用 nc(netcat,更强大)
nc -zv example.com 80
# -z: 扫描模式,不发送数据
# -v: 详细输出

# 扫描端口范围
nc -zv example.com 80-100

# 监听端口(测试用)
nc -l 8080  # 在一个终端监听
nc localhost 8080  # 在另一个终端连接

# 测试 UDP 端口
nc -zvu example.com 53

6.2 HTTP 请求测试

# 基本 GET 请求
curl http://localhost:8080

# 查看完整的请求和响应头
curl -v http://localhost:8080

# 只看响应头
curl -I http://localhost:8080

# POST 请求
curl -X POST -d "key=value" http://localhost:8080/api

# POST JSON 数据
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"test","age":25}' \
  http://localhost:8080/api

# 带认证的请求
curl -u username:password http://localhost:8080/api

# 带 Cookie
curl -b "session=abc123" http://localhost:8080

# 保存 Cookie
curl -c cookies.txt http://localhost:8080/login

# 使用保存的 Cookie
curl -b cookies.txt http://localhost:8080/dashboard

# 下载文件
curl -O https://example.com/file.zip

# 指定保存的文件名
curl -o myfile.zip https://example.com/file.zip

# 断点续传
curl -C - -O https://example.com/largefile.zip

# 限速下载(100KB/s)
curl --limit-rate 100K -O https://example.com/file.zip

# 跟随重定向
curl -L http://example.com

# 测试接口响应时间
curl -w "@-" -o /dev/null -s http://localhost:8080 <<'EOF'
    time_namelookup:  %{time_namelookup}\n
       time_connect:  %{time_connect}\n
    time_appconnect:  %{time_appconnect}\n
      time_redirect:  %{time_redirect}\n
   time_pretransfer:  %{time_pretransfer}\n
 time_starttransfer:  %{time_starttransfer}\n
                    ----------\n
         time_total:  %{time_total}\n
EOF

6.3 DNS 查询

# 查询域名的 IP
nslookup google.com

# 更详细的 DNS 查询
dig google.com

# 只显示 IP 地址
dig +short google.com

# 查询 MX 记录(邮件服务器)
dig google.com MX

# 查询 DNS 记录类型
dig google.com ANY

# 指定 DNS 服务器查询
dig @8.8.8.8 google.com

# 反向查询(IP 查域名)
dig -x 8.8.8.8

# 使用 host 命令
host google.com

6.4 路由追踪

# 追踪到目标的网络路径
traceroute google.com

# 或用 tracepath(不需要 root)
tracepath google.com

# 使用 mtr(更好的追踪工具)
mtr google.com
# 实时显示每一跳的延迟和丢包率

6.5 网络连接查看

# 查看所有网络连接
ss -tunapr

# 查看建立的连接
ss -tn state established

# 查看监听的端口
ss -tln

# 查看哪些进程连接到远程服务器
ss -tnp | grep 443

# 统计连接状态
ss -tan | awk '{print $1}' | sort | uniq -c

# 查看网络接口
ip addr show

# 查看路由表
ip route show

# 查看 ARP 表
ip neigh show

6.6 抓包分析

# 安装 tcpdump
sudo apt install tcpdump

# 抓取所有网卡的包
sudo tcpdump

# 抓取指定网卡
sudo tcpdump -i eth0

# 抓取指定端口
sudo tcpdump port 80

# 抓取指定 IP
sudo tcpdump host 192.168.1.100

# 抓取并保存到文件
sudo tcpdump -i eth0 -w capture.pcap

# 读取抓包文件
sudo tcpdump -r capture.pcap

# 只抓取 HTTP 请求
sudo tcpdump -i eth0 -A 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420)'

# 抓取特定数量的包
sudo tcpdump -c 100

# 显示详细信息
sudo tcpdump -v port 80

6.7 防火墙管理

# 查看防火墙状态
sudo ufw status

# 查看详细规则(带编号)
sudo ufw status numbered

# 允许某个端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 22/tcp  # SSH,小心别把自己锁外面

# 允许端口范围
sudo ufw allow 6000:6010/tcp

# 允许特定 IP 访问
sudo ufw allow from 192.168.1.100

# 允许特定 IP 访问特定端口
sudo ufw allow from 192.168.1.100 to any port 22

# 拒绝连接
sudo ufw deny 23/tcp

# 删除规则(按编号)
sudo ufw delete 3

# 删除规则(按规则内容)
sudo ufw delete allow 80/tcp

# 启用防火墙
sudo ufw enable

# 禁用防火墙
sudo ufw disable

# 重置所有规则
sudo ufw reset

# 查看应用配置文件
sudo ufw app list

# 使用应用配置
sudo ufw allow 'Nginx Full'

6.8 网速测试

# 安装 speedtest
sudo apt install speedtest-cli

# 测试网速
speedtest-cli

# 只测试下载速度
speedtest-cli --no-upload

# 用字节显示(而不是比特)
speedtest-cli --bytes

# 使用 iperf3 测试局域网速度
# 服务器端:
iperf3 -s

# 客户端:
iperf3 -c 192.168.1.100

七、系统监控与性能分析

7.1 资源使用监控

# 查看内存使用
free -h

# 持续监控内存(每 2 秒刷新)
watch -n 2 free -h

# 查看内存详细信息
cat /proc/meminfo

# 查看 CPU 信息
lscpu

# 查看 CPU 使用率
top
# 按 1: 显示每个 CPU 核心
# 按 P: 按 CPU 排序
# 按 M: 按内存排序
# 按 k: 杀掉进程

# 更友好的 top(需安装)
htop
# F2: 设置
# F3: 搜索进程
# F4: 过滤
# F5: 树状显示
# F9: 杀进程
# F10: 退出

# 查看系统负载
uptime
# 显示: 运行时间, 用户数, 1/5/15 分钟平均负载

# 查看负载详情
w

7.2 磁盘 I/O 监控

# 实时查看磁盘 I/O
iostat -x 2
# 每 2 秒刷新一次

# 查看哪些进程在读写磁盘
sudo iotop

# 只显示正在读写的进程
sudo iotop -o

# 查看磁盘读写统计
sudo iotop -a

# 使用 pidstat 查看进程 I/O
pidstat -d 2

7.3 进程详细分析

# 查看进程树
pstree

# 查看某个进程的树
pstree -p 1234

# 查看进程详细信息
ps aux | grep nginx

# 查看进程的线程
ps -T -p 1234

# 查看进程打开的文件描述符数量
lsof -p 1234 | wc -l

# 查看进程的环境变量
cat /proc/1234/environ | tr '\0' '\n'

# 查看进程的命令行参数
cat /proc/1234/cmdline

# 查看进程的内存映射
cat /proc/1234/maps

# 查看进程的资源限制
cat /proc/1234/limits

# 使用 pidstat 监控进程
pidstat -p 1234 2
# 每 2 秒显示进程 1234 的统计

7.4 系统日志查看

# 查看系统日志
sudo tail -f /var/log/syslog

# 查看认证日志(登录记录)
sudo tail -f /var/log/auth.log

# 查看内核日志
dmesg

# 实时查看内核日志
dmesg -w

# 查看内核错误
dmesg --level=err

# 查看最近的启动日志
journalctl -b

# 查看上一次启动的日志
journalctl -b -1

# 查看所有启动记录
journalctl --list-boots

# 查看内核日志
journalctl -k

# 查看某个时间后的所有日志
journalctl --since "2024-10-20 10:00"

# 查看特定优先级的日志
journalctl -p err
# 优先级: emerg, alert, crit, err, warning, notice, info, debug

# 查看磁盘使用情况
journalctl --disk-usage

# 清理旧日志(保留最近 100MB)
sudo journalctl --vacuum-size=100M

# 清理 7 天前的日志
sudo journalctl --vacuum-time=7d

7.5 性能分析工具

# 查看系统调用
strace ls
# 跟踪 ls 命令的系统调用

# 跟踪正在运行的进程
sudo strace -p 1234

# 统计系统调用
strace -c ls

# 查看进程打开的文件
sudo strace -e open,openat ls

# 使用 ltrace 跟踪库函数调用
ltrace ls

# 使用 perf 进行性能分析(需安装)
sudo perf top
# 实时显示 CPU 热点

# 记录性能数据
sudo perf record -a -g sleep 10

# 查看性能报告
sudo perf report

# 查看系统瓶颈
vmstat 2
# 每 2 秒显示一次虚拟内存统计

# 查看 CPU 统计
mpstat 2

7.6 网络流量监控

# 实时监控网络流量
sudo iftop
# 按 t: 切换显示模式
# 按 h: 帮助
# 按 q: 退出

# 按连接显示流量
sudo iftop -P

# 监控特定网卡
sudo iftop -i eth0

# 使用 nethogs 按进程监控流量
sudo nethogs

# 监控特定网卡
sudo nethogs eth0

# 使用 vnstat 统计流量(需先配置)
vnstat
vnstat -d  # 按天统计
vnstat -m  # 按月统计
vnstat -h  # 按小时统计

八、实用技巧合集

8.1 批量操作

# 批量重命名(把所有 .txt 改成 .md)
for file in *.txt; do mv "$file" "${file%.txt}.md"; done

# 批量删除某类文件
find . -name "*.log" -delete

# 批量修改权限
find /var/www -type f -exec chmod 644 {} \;
find /var/www -type d -exec chmod 755 {} \;

8.2 压缩与解压

# 打包并压缩
tar -czf archive.tar.gz /path/to/directory

# 解压
tar -xzf archive.tar.gz

# 只查看压缩包内容,不解压
tar -tzf archive.tar.gz

# zip 格式
zip -r archive.zip /path/to/directory
unzip archive.zip

8.3 定时任务

# 编辑定时任务
crontab -e

# 常用格式:
# * * * * * command
# 分 时 日 月 周

# 示例:每天凌晨 2 点备份
0 2 * * * /home/user/backup.sh

# 每 5 分钟执行一次
*/5 * * * * /home/user/check.sh

# 查看当前的定时任务
crontab -l

8.4 命令行快捷操作

# 快速创建多级目录
mkdir -p /path/to/nested/directory

# 同时创建文件和父目录
mkdir -p /path/to && touch /path/to/file.txt

# 切换到上一个目录
cd -

# 快速备份文件
cp file.conf{,.bak}  # 等同于 cp file.conf file.conf.bak

# 清空文件内容
> file.txt

# 快速生成大文件(测试用)
dd if=/dev/zero of=test.img bs=1M count=100

九、故障排查实战手册

9.1 服务启动失败排查

完整排查流程:

# 第一步: 查看服务状态
sudo systemctl status servicename
# 看输出的错误信息和退出码

# 第二步: 查看详细日志
sudo journalctl -u servicename -n 100 --no-pager
# 看最近 100 行日志,找错误信息

# 第三步: 实时查看启动过程
sudo journalctl -u servicename -f
# 在另一个终端尝试启动服务
sudo systemctl start servicename

# 第四步: 检查配置文件语法
# Nginx:
sudo nginx -t

# Apache:
sudo apache2ctl configtest

# MySQL:
sudo mysqld --validate-config

# 第五步: 检查端口占用
sudo lsof -i :80
sudo ss -tlnp | grep :80

# 第六步: 检查文件权限
ls -l /etc/nginx/nginx.conf
ls -ld /var/www/html

# 第七步: 检查 SELinux/AppArmor
sudo aa-status  # AppArmor
getenforce      # SELinux

# 第八步: 手动运行程序看错误
# 找到服务的 ExecStart 命令
sudo systemctl cat servicename
# 手动执行那个命令

# 第九步: 查看系统日志
sudo tail -n 50 /var/log/syslog | grep servicename

# 第十步: 检查依赖服务
sudo systemctl list-dependencies servicename

常见错误及解决:

# 错误: Address already in use
# 解决: 杀掉占用端口的进程
sudo lsof -ti :80 | xargs sudo kill -9

# 错误: Permission denied
# 解决: 检查文件权限和所有者
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html

# 错误: No such file or directory
# 解决: 创建缺失的目录
sudo mkdir -p /var/log/myapp
sudo chown myuser:myuser /var/log/myapp

# 错误: Failed to start (timeout)
# 解决: 增加启动超时时间
# 编辑服务文件,添加:
# TimeoutStartSec=300

9.2 磁盘空间不足排查

# 第一步: 查看磁盘使用情况
df -h

# 第二步: 找出占用空间最大的目录
sudo du -h / --max-depth=1 2>/dev/null | sort -rh | head -10

# 第三步: 深入查看大目录
sudo du -h /var --max-depth=1 | sort -rh | head -10

# 第四步: 找出最大的文件
sudo find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null | awk '{print $5, $9}' | sort -rh | head -20

# 第五步: 查看已删除但仍被占用的文件
sudo lsof | grep deleted | sort -k7 -rn

# 第六步: 清理方案

# 清理包管理器缓存
sudo apt clean
sudo apt autoremove

# 清理日志(保留最近 100MB)
sudo journalctl --vacuum-size=100M

# 清理旧日志文件
sudo find /var/log -name "*.gz" -delete
sudo find /var/log -name "*.1" -delete

# 清理 Docker(如果使用)
docker system prune -a

# 清理 snap 旧版本
sudo snap list --all | awk '/disabled/{print $1, $3}' | while read name revision; do sudo snap remove "$name" --revision="$revision"; done

# 清理临时文件
sudo rm -rf /tmp/*
sudo rm -rf /var/tmp/*

# 清理缩略图缓存
rm -rf ~/.cache/thumbnails/*

# 第七步: 找出僵尸文件(已删除但进程仍打开)
sudo lsof +L1
# 需要重启相关进程来释放空间

9.3 网络不通排查

# 第一步: 检查网卡状态
ip addr show
# 确认网卡有 IP 地址

# 第二步: 检查网卡是否 up
ip link show
# 如果显示 DOWN:
sudo ip link set eth0 up

# 第三步: 检查本机网络
ping 127.0.0.1

# 第四步: 检查网关
ip route show
# 记下网关 IP,然后 ping
ping 192.168.1.1

# 第五步: 检查 DNS
cat /etc/resolv.conf
# 测试 DNS 解析
nslookup google.com
# 如果失败,尝试:
echo "nameserver 8.8.8.8" | sudo tee -a /etc/resolv.conf

# 第六步: 测试外网连通性
ping 8.8.8.8
# 如果通,说明网络正常,DNS 有问题

# 第七步: 检查防火墙规则
sudo iptables -L -n
sudo ufw status

# 第八步: 检查路由表
ip route show
netstat -rn

# 第九步: 追踪路由
traceroute google.com
mtr google.com

# 第十步: 检查网络服务
sudo systemctl status NetworkManager
sudo systemctl status systemd-networkd

9.4 进程僵死/卡死排查

# 第一步: 找到进程
ps aux | grep processname

# 第二步: 查看进程状态
ps -o pid,stat,cmd -p 1234
# STAT 含义:
# D: 不可中断睡眠(通常是 I/O)
# R: 运行中
# S: 睡眠
# T: 停止
# Z: 僵尸进程

# 第三步: 查看进程在做什么
sudo strace -p 1234

# 第四步: 查看进程的文件操作
sudo lsof -p 1234

# 第五步: 查看进程的系统调用
sudo cat /proc/1234/stack

# 第六步: 生成进程堆栈
sudo gdb -p 1234 -batch -ex "thread apply all bt"

# 第七步: 查看进程的 CPU 使用
top -p 1234

# 第八步: 尝试正常终止
kill -15 1234
# 等待 10 秒

# 第九步: 强制终止
kill -9 1234

# 如果是僵尸进程(Z 状态):
# 找到父进程
ps -o ppid= -p 1234
# 杀掉父进程
sudo kill -9 <ppid>

9.5 内存不足/泄漏排查

# 第一步: 查看内存使用
free -h
# 看 available 这一列

# 第二步: 找出内存占用最大的进程
ps aux --sort=-%mem | head -10

# 第三步: 查看进程的详细内存
sudo pmap -x 1234

# 第四步: 实时监控内存变化
watch -n 1 'ps aux --sort=-%mem | head -10'

# 第五步: 查看内存映射
sudo cat /proc/1234/smaps

# 第六步: 检查是否有内存泄漏
# 持续观察某个进程的内存占用
while true; do
  ps -o pid,vsz,rss,cmd -p 1234
  sleep 5
done

# 第七步: 查看 OOM 杀进程记录
sudo dmesg | grep -i "killed process"
sudo journalctl -k | grep -i "killed process"

# 第八步: 临时释放缓存(不推荐,除非紧急)
sudo sync
echo 3 | sudo tee /proc/sys/vm/drop_caches

9.6 高 CPU 占用排查

# 第一步: 找出 CPU 占用高的进程
top
# 按 P 按 CPU 排序

# 或者:
ps aux --sort=-%cpu | head -10

# 第二步: 查看进程的线程
top -H -p 1234
# 找出哪个线程占用高

# 第三步: 转换线程 ID 为十六进制
printf "%x\n" 1234

# 第四步: 查看线程堆栈
sudo cat /proc/1234/task/*/stack

# 第五步: 使用 perf 分析
sudo perf top -p 1234

# 或者记录 10 秒的性能数据
sudo perf record -p 1234 -g sleep 10
sudo perf report

# 第六步: 查看进程的系统调用
sudo strace -c -p 1234

# 第七步: 检查是否是死循环
sudo strace -p 1234 2>&1 | head -100

9.7 SSH 登录问题排查

# 场景一: 连接超时
# 检查网络连通性
ping server_ip

# 检查端口是否开放
nc -zv server_ip 22

# 检查防火墙
sudo ufw status

# 场景二: Permission denied
# 检查 SSH 服务状态
sudo systemctl status ssh

# 查看 SSH 日志
sudo tail -f /var/log/auth.log

# 检查 SSH 配置
sudo nano /etc/ssh/sshd_config
# 确认:
# PermitRootLogin yes/no
# PasswordAuthentication yes/no
# PubkeyAuthentication yes

# 重启 SSH 服务
sudo systemctl restart ssh

# 场景三: 密钥认证失败
# 检查密钥权限
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

# 检查密钥内容
cat ~/.ssh/authorized_keys

# 在客户端测试连接
ssh -v user@server_ip
# 看详细输出找问题

9.8 文件系统问题排查

# 文件系统只读
# 查看挂载状态
mount | grep "on / "

# 重新挂载为读写
sudo mount -o remount,rw /

# 检查文件系统错误
sudo fsck /dev/sda1
# 注意: 必须先卸载分区或在救援模式下运行

# 查看磁盘健康状态
sudo smartctl -a /dev/sda

# 查看 I/O 错误
dmesg | grep -i error
sudo journalctl -k | grep -i "I/O error"

# 查看文件系统 inode 使用
df -i

# inode 用完的解决:
# 找出文件数量最多的目录
sudo find / -xdev -type f | cut -d "/" -f 2 | sort | uniq -c | sort -rn | head -10

# 删除不需要的小文件
sudo find /tmp -type f -delete

9.9 快速诊断脚本

创建一个一键诊断脚本:

#!/bin/bash
# system_check.sh - 系统快速诊断

echo "========== 系统基本信息 =========="
uname -a
uptime

echo -e "\n========== CPU 使用 TOP 5 =========="
ps aux --sort=-%cpu | head -6

echo -e "\n========== 内存使用 TOP 5 =========="
ps aux --sort=-%mem | head -6

echo -e "\n========== 内存状态 =========="
free -h

echo -e "\n========== 磁盘使用 =========="
df -h

echo -e "\n========== 磁盘 I/O =========="
iostat -x 1 2 | tail -n +4

echo -e "\n========== 网络连接统计 =========="
ss -s

echo -e "\n========== 监听端口 =========="
ss -tlnp

echo -e "\n========== 最近的系统错误 =========="
journalctl -p err -n 10 --no-pager

echo -e "\n========== 最近登录记录 =========="
last -n 10

echo -e "\n========== 失败的服务 =========="
systemctl --failed

使用:

chmod +x system_check.sh
sudo ./system_check.sh

十、进阶技巧与最佳实践

10.1 别名(Alias)提高效率

设置常用别名:

# 编辑 bash 配置
nano ~/.bashrc

# 在文件末尾添加:
alias ll='ls -alh'
alias la='ls -A'
alias l='ls -CF'
alias ..='cd ..'
alias ...='cd ../..'
alias grep='grep --color=auto'

# 常用系统命令别名
alias update='sudo apt update && sudo apt upgrade'
alias install='sudo apt install'
alias remove='sudo apt remove'
alias search='apt search'

# 快速查看日志
alias syslog='sudo tail -f /var/log/syslog'
alias authlog='sudo tail -f /var/log/auth.log'

# 网络相关
alias ports='sudo netstat -tulnp'
alias listening='sudo lsof -i -P -n | grep LISTEN'

# 进程相关
alias psmem='ps aux --sort=-%mem | head'
alias pscpu='ps aux --sort=-%cpu | head'

# Docker 相关(如果使用)
alias dps='docker ps'
alias dpa='docker ps -a'
alias di='docker images'
alias dlog='docker logs -f'

# Git 相关
alias gs='git status'
alias ga='git add'
alias gc='git commit'
alias gp='git push'
alias gl='git log --oneline'

# 使别名生效
source ~/.bashrc

# 查看所有别名
alias

# 临时禁用别名(使用原始命令)
\ls  # 前面加反斜杠

10.2 环境变量管理

# 查看所有环境变量
env
printenv

# 查看特定变量
echo $PATH
echo $HOME

# 临时设置变量(当前 shell 有效)
export MY_VAR="value"

# 永久设置(当前用户)
nano ~/.bashrc
# 添加:
export MY_VAR="value"
export PATH=$PATH:/opt/myapp/bin

# 永久设置(所有用户)
sudo nano /etc/environment
# 添加:
MY_VAR="value"

# 使变量生效
source ~/.bashrc

# 删除变量
unset MY_VAR

10.3 输入输出重定向

# 标准输出重定向
ls > output.txt         # 覆盖
ls >> output.txt        # 追加

# 标准错误重定向
command 2> error.txt

# 同时重定向输出和错误
command > output.txt 2>&1
command &> output.txt    # 简写

# 分别重定向
command > output.txt 2> error.txt

# 丢弃输出
command > /dev/null 2>&1

# 输入重定向
command < input.txt

# Here Document
cat << EOF > file.txt
line 1
line 2
EOF

# Here String
grep "pattern" <<< "test string"

10.4 管道与命令组合

# 管道: 前一个命令的输出作为后一个的输入
ps aux | grep nginx | awk '{print $2}'

# 统计行数
ps aux | wc -l

# 排序并去重
cat file.txt | sort | uniq

# 计数重复行
cat file.txt | sort | uniq -c

# xargs: 将标准输入转为命令参数
find . -name "*.tmp" | xargs rm
find . -name "*.log" -print0 | xargs -0 rm  # 处理文件名有空格的情况

# tee: 同时输出到屏幕和文件
ls -la | tee output.txt

# 命令替换
echo "Today is $(date)"
echo "Files: $(ls | wc -l)"

# 命令组合
cd /var/log && ls -lh  # 前面成功才执行后面
cd /nonexist || echo "Failed"  # 前面失败才执行后面
mkdir test && cd test  # 常用组合

10.5 循环与条件

在命令行中使用循环:

# for 循环
for i in {1..5}; do echo "Number $i"; done

# 遍历文件
for file in *.txt; do echo "Processing $file"; done

# while 循环
i=1; while [ $i -le 5 ]; do echo $i; ((i++)); done

# 批量重命名
for file in *.txt; do mv "$file" "${file%.txt}.md"; done

# 批量下载
for i in {1..10}; do wget "http://example.com/file$i.zip"; done

# 条件判断
if [ -f file.txt ]; then echo "File exists"; else echo "Not found"; fi

# 检查目录
if [ -d /var/log ]; then cd /var/log; fi

# 检查命令是否存在
if command -v docker &> /dev/null; then echo "Docker installed"; fi

10.6 脚本调试

# 显示执行的每一条命令
bash -x script.sh

# 在脚本开头添加
#!/bin/bash
set -x  # 显示执行的命令
set -e  # 遇到错误立即退出
set -u  # 使用未定义变量时报错
set -o pipefail  # 管道中任何命令失败都算失败

# 或者一行搞定
set -euxo pipefail

# 调试特定部分
set -x
# 要调试的代码
set +x

# 使用 shellcheck 检查脚本
sudo apt install shellcheck
shellcheck script.sh

10.7 文本处理神器

sed 实用示例:

# 替换文本(不修改原文件)
sed 's/old/new/' file.txt

# 替换所有匹配(不只是第一个)
sed 's/old/new/g' file.txt

# 直接修改文件
sed -i 's/old/new/g' file.txt

# 删除空行
sed '/^$/d' file.txt

# 删除包含某个词的行
sed '/pattern/d' file.txt

# 在第 3 行后插入内容
sed '3a\New line' file.txt

# 替换第 5 行
sed '5c\New content' file.txt

# 只处理第 2 到第 5 行
sed '2,5s/old/new/g' file.txt

awk 实用示例:

# 打印第一列
awk '{print $1}' file.txt

# 打印第一和第三列
awk '{print $1, $3}' file.txt

# 使用不同的分隔符
awk -F ':' '{print $1}' /etc/passwd

# 条件过滤
awk '$3 > 100' file.txt

# 计算总和
awk '{sum += $1} END {print sum}' file.txt

# 统计行数
awk 'END {print NR}' file.txt

# 格式化输出
awk '{printf "%-10s %s\n", $1, $2}' file.txt

# Nginx 日志分析: 统计状态码
awk '{print $9}' access.log | sort | uniq -c | sort -rn

# 统计 IP 访问量
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

# 计算平均响应时间
awk '{sum+=$NF} END {print sum/NR}' time.log

10.8 定时任务进阶

# 编辑 crontab
crontab -e

# Crontab 格式:
# ┌─────── 分钟 (0-59)
# │ ┌───── 小时 (0-23)
# │ │ ┌─── 日期 (1-31)
# │ │ │ ┌─ 月份 (1-12)
# │ │ │ │ ┌ 星期 (0-6, 0=周日)
# │ │ │ │ │
# * * * * * command

# 实用示例:
# 每分钟执行
* * * * * /path/to/script.sh

# 每 5 分钟
*/5 * * * * /path/to/script.sh

# 每小时的第 30 分钟
30 * * * * /path/to/script.sh

# 每天凌晨 2 点
0 2 * * * /path/to/script.sh

# 每周一上午 9 点
0 9 * * 1 /path/to/script.sh

# 每月 1 号凌晨 3 点
0 3 1 * * /path/to/script.sh

# 工作日早上 8 点
0 8 * * 1-5 /path/to/script.sh

# 重定向输出和错误
0 2 * * * /path/to/script.sh >> /var/log/backup.log 2>&1

# 设置环境变量
0 2 * * * export PATH=/usr/local/bin:$PATH && /path/to/script.sh

# 查看 cron 日志
sudo tail -f /var/log/syslog | grep CRON

# 系统级定时任务(在 /etc/cron.d/ 创建文件)
sudo nano /etc/cron.d/myapp
# 格式: 分 时 日 月 周 用户 命令
0 2 * * * root /path/to/script.sh

10.9 SSH 进阶技巧

# SSH 密钥认证
ssh-keygen -t rsa -b 4096 -C "[email protected]"
ssh-copy-id user@server

# SSH 配置文件(~/.ssh/config)
nano ~/.ssh/config

# 内容示例:
Host myserver
    HostName 192.168.1.100
    User ubuntu
    Port 22
    IdentityFile ~/.ssh/id_rsa

# 使用: ssh myserver

# SSH 端口转发
# 本地转发: 访问本地 8080 -> 转发到远程 80
ssh -L 8080:localhost:80 user@server

# 远程转发: 远程访问 8080 -> 转发到本地 80
ssh -R 8080:localhost:80 user@server

# 动态转发(SOCKS 代理)
ssh -D 1080 user@server

# 保持连接
# 在 ~/.ssh/config 添加:
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

# SSH 跳板机
ssh -J jumphost targethost

# 后台运行 SSH 连接
ssh -fN -L 8080:localhost:80 user@server

# SCP 文件传输
scp file.txt user@server:/path/to/destination
scp -r directory/ user@server:/path/
scp user@server:/path/file.txt ./

# rsync 同步(更强大)
rsync -avz source/ user@server:/destination/
rsync -avz --delete source/ user@server:/destination/  # 删除目标多余文件
rsync -avz -e "ssh -p 2222" source/ user@server:/dest/  # 指定端口

10.10 实用单行命令

# 快速启动 HTTP 服务器(分享文件)
python3 -m http.server 8000

# 生成随机密码
openssl rand -base64 16

# 查看哪些用户在线
w
who

# 查看登录历史
last
last -10  # 最近 10 次

# 查看失败的登录尝试
sudo lastb

# 显示文件的十六进制
xxd file.bin

# 对比两个文件
diff file1.txt file2.txt
diff -u file1.txt file2.txt  # 统一格式
vimdiff file1.txt file2.txt  # 可视化对比

# 批量替换文件内容
find . -name "*.txt" -exec sed -i 's/old/new/g' {} \;

# 查找并删除空目录
find . -type d -empty -delete

# 查看文件的创建/修改时间
stat file.txt

# 快速备份文件
cp important.conf{,.backup}

# 创建目录并进入
mkdir -p project/src && cd $_

# 上一个命令的最后一个参数
echo $_

# 清空文件但保留文件
> file.txt

# 比较两个目录
diff -rq dir1/ dir2/

# 监控文件变化
watch -d -n 1 'ls -lh file.txt'

# 查看进程树
pstree -p

# 在后台解压大文件
nohup tar -xzf large.tar.

命令行的学习是一个持续的过程,不需要一次记住所有命令。建议:

  1. 收藏这篇文章,遇到问题时快速查找
  2. 用到什么学什么,不要死记硬背
  3. 使用 Tab 键自动补全,提高效率减少错误
  4. 建立自己的命令片段库,把常用的命令保存到笔记里

善用 --helpman:大部分命令都有帮助文档

nginx --helpman systemctl

最重要的是:不要怕敲错命令,Linux 不会轻易让你搞坏系统(除非你 sudo rm -rf /)。多练习,你很快就能熟练掌握这些工具。

Read more

一次意想不到的性能问题排查

一次意想不到的性能问题排查

最近几天遇到了一个令人头疼的问题:后端 API 接口响应越来越慢,有时甚至会出现假死状态,完全无法响应请求。唯一的临时解决方案是重启后端服务,但过不了多久问题又会重现。 初期症状: * API 响应时间从几十毫秒逐渐增长到几秒 * 随着服务运行时间增长,性能持续下降 * 最终会进入假死状态,必须重启才能恢复 * 重启后短时间内运行正常,然后重蹈覆辙 排查过程 这种"越跑越慢"的症状让我首先怀疑是内存泄漏或资源未释放。我尝试了多种方向: 1. 优化缓存策略 面对性能问题,第一反应是减少不必要的计算和请求: 后端 Redis 缓存 * 将频繁查询的数据加入 Redis 缓存 * 对热点接口实施缓存层 * 设置合理的缓存过期时间 前端静态资源优化 // 为静态文件添加版本号/随机码,实现持久化缓存 <script src="/app.js?v=a8f3c2d1">

By 王圆圆
理解爱

理解爱

一、童年的禁忌 童年时期,我对"爱"这个字有一种说不清的抗拒。那时候如果喜欢上某个女孩子,我会感到羞耻,仿佛这是一种不该有的情感。我不知道这种感觉从何而来,只是本能地觉得——这样不对。 中学时借宿在邻居家,几个同龄男孩在夜里聊起那些露骨的话题,讨论女人的身体如同讨论一件器物。我坐在黑暗里,心中涌起强烈的抗拒。我觉得女性是神圣的,怎么能被如此低俗地对待,被工具化成谈资和玩物?那一刻,我认定他们是"坏孩子",而我守护着某种更高尚的东西。 大学时代,周围充斥着粗俗的口头禅和随意的恋爱观。有人把恋爱当作满足生理需求的手段,我在心里不屑——这种爱不干净,这不是我理解的爱。 二、理想的碎片 毕业后独自生活,我始终与女孩子保持着某种距离。我心里有个信念:女孩子应该被保护、被关爱。这个信念像一面镜子,让我用特定的方式打量这个世界。 然而,当我真正进入职场,与形形色色的女性共事后,我的理想开始出现裂痕。我发现有些女孩子会利用自己的性别优势,她们结成小团体,排斥异己。

By 王圆圆
一巴掌的温度

一巴掌的温度

为什么天空是蓝的?为什么东西会掉下来?还有——一巴掌下去,能把你打熟吗?今天,我们就来认真地(一本正经)讨论下这个问题。 有人曾经算过:如果你的手掌能以1667米/秒(约6000公里/小时)的速度拍打一只鸡,它就能被"打熟"。(没飞的情况下) 听起来很科学?但这只是让鸡瞬间升温所需的能量。真正打熟,还得在那个温度保持一段时间。除非你一巴掌把它打得够烫,烫到冷却过程中就能熟完,否则一次拍打根本不够。 想搞清楚这个问题,就得考虑鸡肉怎么散热。任何温度高于绝对零度的物体都会不停向外辐射热量,这叫黑体辐射——白炽灯发光、烧红的玻璃,都是这个道理。要保持温度,就得不断补充散失的能量。 一只普通大小、加热到74°C的整鸡(美国FDA规定的安全食用温度),每秒散发约2000瓦的热量——相当于300支节能灯泡同时开着。 为了方便计算,我们假设:把鸡吊在真空舱里(避免空气带走热量),你和三个朋友穿上宇航服,轮流扇巴掌。 要在几分钟内让鸡保持74°C并打熟,

By 王圆圆