常用 Linux Shell 命令
系统监控与资源排查-快速定位资源瓶颈
查看CPU/内存/根分区
# top -b -n 1:非交互模式输出 1 次系统状态,避免进入 top 交互界面
# grep Cpu:过滤 CPU 行,awk提取使用率
# free -h:人性化显示内存,grep Mem聚焦内存行
# df -h | grep /$:只看根分区(避免显示其他挂载点),提取使用率和空闲空间
## 若根分区挂载点不是/(比如特殊系统),需把grep /$改成实际挂载点(如grep /root)
top -b -n 1 | grep Cpu | awk '{print "CPU使用率:"$2"%"}' && free -h | grep Mem | awk '{print "内存使用率:"$3"/"$2"("$7"空闲)"}' && df -h | grep /$ | awk '{print "根分区使用率:"$5"("$4"空闲)"}'
输出
CPU使用率:0.0%
内存使用率:95M/470M(327M空闲)
根分区使用率:20%(6.5G空闲)
CPU/内存排序
# ps -eo:自定义输出字段(pid = 进程 ID,ppid = 父进程 ID,% cpu=CPU 占比,% mem = 内存占比,cmd = 进程命令)
# --sort=-%cpu:按 CPU 占比倒序排列(-表示倒序)
## 若想查 "吃内存最多" 的进程,把--sort=-%cpu改成--sort=-%mem
# head -10:只显示前 10 条,避免输出过长
ps -eo pid,ppid,%cpu,%mem,cmd --sort=-%cpu | head -10
输出
PID PPID %CPU %MEM CMD
1 0 0.0 0.7 /usr/lib/systemd/systemd --system --deserialize 16
2 0 0.0 0.0 [kthreadd]
3 2 0.0 0.0 [ksoftirqd/0]
5 2 0.0 0.0 [kworker/0:0H]
7 2 0.0 0.0 [migration/0]
8 2 0.0 0.0 [rcu_bh]
9 2 0.0 0.0 [rcu_sched]
10 2 0.0 0.0 [lru-add-drain]
11 2 0.0 0.0 [watchdog/0]
查看大文件
# find / -type f -size +100M:从根目录找所有大小超过 100M 的文件(-type f指定文件,避免目录)
## 若想找 "大于 1G" 的文件,把+100M改成+1G
# 2>/dev/null:忽略权限不足的报错(比如/proc目录下的文件)
# xargs du -sh:对找到的文件逐个计算大小(-s单文件,-h人性化显示)
# sort -hr:按大小倒序排列(-h识别 "G/M" 单位,-r倒序)
find / -type f -size +100M 2>/dev/null | xargs du -sh | sort -hr
输出
156M /var/cache/yum/x86_64/7/updates/gen/primary_db.sqlite
149M /var/cache/yum/x86_64/7/updates/gen/filelists_db.sqlite
102M /usr/lib/locale/locale-archive
0 /sys/devices/pci0000:00/0000:00:0f.0/resource1_wc
0 /sys/devices/pci0000:00/0000:00:0f.0/resource1
0 /proc/kcore
磁盘IO
# vmstat 1 5:每 1 秒输出 1 次系统 IO 状态,共输出 5 次(避免单次数据不准)
# NR>1:跳过 vmstat 的表头行
# $16:vmstat 输出中 "wa" 字段(IO 等待时间,单位 ms),$17:"st" 字段(等待 IO 的进程数)
## 若 wa 长期超过 20ms,需进一步用iostat -x 1查看具体磁盘的 IO 情况(如sda的 util% 是否接近 100%)
vmstat 1 5 | awk 'NR>1 {print "平均等待IO时间:"$16"ms 等待IO进程数:"$17"个"}'
输出
平均等待IO时间:wams 等待IO进程数:st个
平均等待IO时间:0ms 等待IO进程数:0个
平均等待IO时间:0ms 等待IO进程数:0个
平均等待IO时间:0ms 等待IO进程数:0个
平均等待IO时间:0ms 等待IO进程数:0个
平均等待IO时间:0ms 等待IO进程数:0个
网卡实时流量
# sar -n DEV 1 3:每 1 秒输出 1 次网卡流量,共 3 次(-n DEV指定网卡统计)
# grep -v Average:排除最后一行的平均值(只看实时数据)
# awk '/eth0/:只过滤 eth0 网卡的行,$5是接收流量(rxkB/s),$6是发送流量(txkB/s)
## eth0根据实际情况修改
sar -n DEV 1 3 | grep -v Average | awk '/eth0/ {print "网卡eth0:接收"$5"KB/s 发送"$6"KB/s"}'
输出
网卡eth0:接收0.00KB/s 发送0.06KB/s
网卡eth0:接收0.00KB/s 发送0.00KB/s
网卡eth0:接收0.00KB/s 发送0.00KB/s
当前在线的用户
# w:查看当前登录用户及操作
# NR>1:跳过 w 的表头
# $1是用户名,$3是登录 IP(若本地登录是localhost),$4是登录时间
## 若想查 "历史登录记录",改用last -n 10(显示最近 10 次登录)
w | awk 'NR>1 {print "登录用户:"$1" 登录IP:"$3" 登录时间:"$4}'
输出
登录用户:USER 登录IP:FROM 登录时间:LOGIN@
登录用户:root 登录IP:15:37 登录时间:45:51
登录用户:root 登录IP:192.168.200.8 登录时间:17:02
登录用户:root 登录IP:192.168.200.8 登录时间:17:18
登录用户:root 登录IP:192.168.200.8 登录时间:18:48
登录用户:root 登录IP:192.168.200.8 登录时间:23:01
日志分析与数据提取-分析日志
正则匹配筛选和统计
# grep -i "error":忽略大小写找含 "error" 的行(避免漏 "Error""ERROR")
# grep -E "2025-11-11":用正则匹配指定日期(日志需带时间戳,Nginx 默认日志格式含日期)
# wc -l:统计符合条件的行数(即错误次数)
grep -i "error" /var/log/xxx.log | grep -E "2025-11-11" | wc -l
输出
100
正则匹配筛选和排序
# grep "500":过滤状态码为 500 的请求($9是 Nginx 日志的状态码字段)
# awk '{print $1,$7,$9}':提取 IP($1)、URL($7)、状态码($9)
## 使用 head -1 xxx.log 看日志结构,再修改 awk 序号
# sort | uniq -c:按 "IP+URL" 去重并统计次数(uniq -c计数)
# sort -nr:按次数倒序,head -10取前 10
grep "500" /var/log/xxx.log | awk '{print $1,$7,$9}' | sort | uniq -c | sort -nr | head -10
输出
192.168.1.1 /api/info 500
192.168.1.2 /api/info 500
sed筛选和排序
# sed -n '/开始时间/,/结束时间/p':提取两个时间戳之间的日志(-n静默模式,p打印匹配内容);
# grep "Exception":过滤含 "Exception" 的异常行
## 根据实际情况修改
sed -n '/2025-11-11 11:00:00/,/2025-11-12 12:00:00/p' /var/log/xxx.log | grep "Exception"
输出
2025-11-11 11:00:00 ERROR [http-nio-8080-exec-1] com.xxx.xxx: NullPointer Exception
awk筛选和排序
# awk -F '|':指定字段分隔符为 "|"(默认是空格)
# print $3:提取第 3 个字段(即接口名)
# sort | uniq -c:去重并统计次数,sort -nr倒序,head -5取前 5
awk -F '|' '{print $3}' /var/log/xxx.log | sort | uniq -c | sort -nr | head -5
输出
100 /api/info
50 /api/version
不解压统计关键词
# zgrep:直接 grep 压缩文件(支持.gz 格式),避免gunzip解压步骤
# wc -l:统计 timeout 错误次数
zgrep "error" /var/log/log.gz | wc -l
输出
100
实时监控 SSH 登录情况
# tail -f:实时跟踪日志文件(新内容会自动输出)
## 部分系统 SSH 日志在/var/log/secure,需把/var/log/messages改成对应路径
# grep --line-buffered "ssh":缓冲每行内容(避免实时输出延迟),过滤含 "ssh" 的行
# awk:区分 "Accepted"(成功登录)和 "Failed"(失败),标注后输出
tail -f /var/log/messages | grep --line-buffered "ssh" | awk '/Accepted/ {print "正常登录:"$0} /Failed/ {print "登录失败:"$0}'
输出
正常登录:Nov 11 12:00:00 ecs-1 sshd-session[1]: Accepted password for root from 192.168.0.1 port 8888 ssh2
正常登录:Nov 11 13:00:00 ecs-2 sshd-session[2]: Accepted password for root from 192.168.0.2 port 8889 ssh2
文件管理与批量操作
查找文件并执行操作
# find /data/backup:指定查找目录
# -name "*.tar.gz":只找后缀为.tar.gz 的文件
# -mtime +7:修改时间超过 7 天(+7表示 7 天前,-7是 7 天内)
## 若想按 "访问时间" 查找,把-mtime改成-atime
# -exec rm -f {} \;:对找到的文件执行删除操作({}代表找到的文件,\;结束 exec 命令)
find /var/log -name "*.tar.gz" -mtime +7 -exec rm -f {} \;
输出
a.tar.gz
b.tar.gz
目录文件遍历与执行操作
# for file in /var/log/*.log:循环遍历所有.log文件
# date +%Y%m%d:生成当前日期(如 20251111)
# mv "$file" "$file.日期":给每个文件加日期后缀(双引号避免文件名含空格时出错)
for file in /var/log/*.log; do mv "$file" "$file.$(date +%Y%m%d)"; done
输出
a.log.20251111
b.log.20251111
sed替换
# sed -i:直接修改文件内容(-i原地替换,不加-i只预览不修改)
# s/旧内容/新内容/g:替换语法(s=substitute,g=global 全局替换,避免只换第一处)
## 若内容含特殊字符(如/),需用\转义,如 s/http:\/\/old.com/http:\/\/new.com/g
# /etc/config/*.conf:指定要修改的文件(所有.conf)
sed -i 's/old_ip=192.168.1.1/old_ip=192.168.1.2/g' /etc/config/*.conf
输出
无
压缩与排除
# tar -zcvf:打包压缩(z用 gzip 压缩,c创建包,v显示过程,f指定包名);
# log_$(date +%Y%m%d).tar.gz:备份包名含日期;
# --exclude=/var/log/log2:排除 logs 目录
## 若要排除多个目录,加多个--exclude(如--exclude=log1 --exclude=log2)
## 备份前确认目标目录空间足够(用 df -h /data/backup 查看)
tar -zcvf /var/log/log_$(date +%Y%m%d).tar.gz /var/log --exclude=/var/log/log2
输出
无
scp跨服复制
大文件传输建议用rsync(支持断点续传),命令是
rsync -avz /var/log/*.tar.gz root@192.168.1.1:/var/log/
# scp -r:远程拷贝(-r递归拷贝目录,这里虽拷贝文件,但加-r不影响,且支持后续拷贝目录);
# root@192.168.1.1:远程服务器用户名和 IP;
# :/var/log/:远程服务器的目标目录
scp -r /var/log/*.tar.gz root@192.168.1.1:/var/log/
输出
无
查找文件权限
# find /data/app:指定查找目录
# -perm 777:只找权限为 777 的文件(777=rwxrwxrwx)
# -type f:只找文件(避免目录,目录 777 风险较低)
# 2>/dev/null:忽略权限不足的报错
find /data/app -perm 777 -type f 2>/dev/null
# 修改为安全权限
chmod 644 /data/app/config/db.conf
输出
120 192.168.1.200
30 10.0.0.5
25 203.0.113.8
查看目录权限
若要给用户加 ACL 权限,用 setfacl -m u:admin:rwx /data/app(给 admin 用户加读写执行权限)
# getfacl /data/app:查看目录的 ACL 权限(比ls -l更详细,支持多用户 / 组权限)
# grep -E "user:|group:":只显示用户和组的 ACL 权限(避免其他冗余信息)
getfacl /data/app | grep -E "user:|group:"
输出
user::rwx # 所有者权限
user:admin:r-x # admin用户有读执行权限
group::r-x # 所属组权限
group:dev:--- # dev组无权限(可能是问题原因)
进程与服务管理-管控服务状态
快速查看Nginx服务状态
# systemctl status nginx:查看 Nginx 服务状态
## 若系统用service命令(如 centos6),把systemctl status nginx改成service nginx status,日志路径改用/var/log/nginx/error.log
# grep -E "active|inactive|failed":只显示核心状态(active = 运行中,inactive = 停止,failed = 失败)
# journalctl -u nginx:查看 Nginx 的系统日志(-u指定服务单元)
# --since "10 minutes ago":只看最近 10 分钟的日志,tail -20 取最后 20 行
systemctl status nginx | grep -E "active|inactive|failed" && journalctl -u nginx --since "10 minutes ago" | tail -20
输出
...
强制关闭进程
# ps -ef | grep nginx:找所有含 "nginx" 的进程
# grep -v grep:排除 "grep nginx" 这个临时进程(避免误杀)
# awk '{print $2}':提取进程 ID($2 是 ps -ef 输出的 PID 字段)
# xargs kill -9:对提取的 PID 执行强制杀死(kill -9是强制终止,kill -15是正常终止,卡死时用-9)
ps -ef | grep nginx | grep -v grep | awk '{print $2}' | xargs kill -9
输出
...
后台启动与日志输出
# nohup:忽略挂断信号(no hang up),终端退出后进程继续运行
# > /data/logs/app.log:把标准输出(stdout,脚本的正常输出)重定向到 app.log
## 确保/data/logs目录存在
# 2>&1:把标准错误(stderr,脚本的错误输出)也重定向到 stdout(即一起写入 app.log)
# 最后一个&:把进程放到后台运行
nohup /data/app/start.sh > /data/logs/app.log 2>&1 &
输出 tail -f /data/logs/app.log
...
检查进程与执行脚本
定时任务配置(crontab -e):每 5 分钟检查一次
*/5 * * * * pgrep -f "app.jar" || nohup /data/app/start.sh > /data/logs/app.log 2>&1 &
# pgrep -f "app.jar":根据进程名(-f匹配完整命令行)查找进程,找到返回 PID,找不到返回非 0 状态码
# ||:逻辑或,只有前面命令失败(进程不存在)时,才执行后面的启动命令(/data/app/start.sh)
## 检查 app.jar 进程是否存在,不存在则启动
pgrep -f "app.jar" || /data/app/start.sh
输出
...
网络连接与故障排查-快速定位网络问题
端口检查
# netstat -tulnp:查看所有监听端口(t=TCP,u=UDP,l= 监听中,n= 显示 IP 和端口(非服务名),p= 显示进程 ID 和名称)
# grep :8080:过滤 8080 端口的监听情况
netstat -tulnp | grep :8080
输出
tcp6 0 0 :::8888 :::* LISTEN 100/java
端口连接排序
Nginx 服务(80 端口)的连接数突然飙升,要 "找出连接 80 端口最多的前 10 个 IP",判断是否有 IP 在恶意发起大量连接(如 CC 攻击)。
# ss -antp:查看所有 TCP 连接(a= 所有,n= 显示 IP 端口,t=TCP,p= 显示进程)
# grep :80:过滤 80 端口的连接
# awk '{print $5}':提取客户端 IP 和端口($5是 ss 输出的 "客户端地址:端口" 字段)
# cut -d: -f1:按 ":" 分割,取 IP 部分(去掉端口)
# sort | uniq -c:统计每个 IP 的连接数,sort -nr倒序,head -10取前 10
ss -antp | grep :80 | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -10
输出
120 192.168.1.200
30 10.0.0.5
25 203.0.113.8