对于 Linux 资深使用者而言,Shell 脚本的功用远不止于 “自动执行命令” 这般浅显。在诸如百万级日志分析、分布式任务调度以及系统资源监控等复杂情境下,普通指令与基础逻辑显然难以胜任。
本文着重聚焦于 10 个高阶指令,并搭配 “日志分析、性能监控、批量运维” 等实战案例,旨在教授读者运用 Shell 编写出 “高效、稳定、可复用” 的进阶脚本,以解决工作中高达 90% 的复杂需求。

一、先明确:老手写 Shell,核心追求是什么?
新手编写脚本追求 “可用”,而老手则追求 “三性”:
- 高效性:能够在处理百万行日志时保持流畅,执行速度相较于基础脚本可提升 10 倍之多。
- 健壮性:具备应对 “磁盘满、网络断、权限不足” 等极端状况的能力,确保脚本不会崩溃或挂起。
- 可维护性:支持参数化调用与模块化拆分,从而保障多人协作时有条不紊。
而达成这 “三性” 的核心要点,便是善用高阶指令与进阶语法。例如,运用 awk 替代 grep + sed 进行日志分析;借助 xargs + parallel 实现多线程执行;利用 trap 捕获信号以防止脚本意外退出。
二、10 个高阶指令实战:从场景到代码,直接抄作业
1、awk:日志分析的 “瑞士军刀”,比 grep + sed 更为高效
核心能力:可按列处理文本、进行自定义逻辑计算以及批量提取关键信息,尤其适用于百万级日志分析。
实战场景:从 Nginx 访问日志(格式:IP 时间 “请求方法 URL” 状态码 响应时间)中,统计 “每个 IP 的请求次数、平均响应时间”,并按请求次数排序。
代码示例:
# 假设Nginx日志路径为/var/log/nginx/access.log
awk '{
ip[$1]++ # 统计每个IP的请求次数,ip是关联数组(键为IP,值为次数)
rt[$1] += $6 # 累加每个IP的总响应时间($6是响应时间列)
}
END {
# 遍历数组,输出IP、请求次数、平均响应时间(保留2位小数)
for (i in ip) {
printf "%-15s %-5d %.2f
", i, ip[i], rt[i]/ip[i]
}
}' /var/log/nginx/access.log | sort -k2 -nr # 按请求次数(第2列)倒序排序
优势:相较于 “grep 提取 IP + sed 处理格式 + wc 统计” 的组合方式,awk 凭借单一指令即可完成多步逻辑,执行效率提升 50% 以上,且代码更为简洁。
2、xargs:批量执行命令的 “连接器”,解决 “参数过长” 问题
核心能力:堪称批量执行命令的 “精妙连接器”,能卓有成效地化解 “参数过长” 这一颇为棘手的难题。其核心优势在于,能够将标准输入,像文件列表、命令输出之类的内容,灵活且精准地转化为命令参数。它不仅有力地支持批量执行操作,还能完美规避 “命令参数过长” 引发的报错状况(举例来说,当文件数量庞大时,直接执行 “rm *.log” 会触发报错,而运用 “ls *.log | xargs rm” 则可顺利执行)。
实战场景:需对 “/data/logs” 目录下生成时间超过 30 天的.log 文件开展批量压缩作业(运用 gzip 进行压缩处理,待压缩完毕后将原文件予以删除)。
代码示例:
# 1. 查找30天前的.log文件;2. 用xargs传递给gzip压缩;3. 压缩后删除原文件
find /data/logs -name "*.log" -mtime +30 | xargs -I {} sh -c "gzip {} && rm -f {}"
# -I {}:把find输出的每个文件路径替换为{},防止文件名包含空格而引发报错
进阶技巧:若添加上 “-P 4” 这一选项,便能启用 4 个并行进程(也就是 “xargs -P 4 -I {} …”)。如此操作之下,压缩速度能够提升至原来的 4 倍。此技巧在处理大量文件的场景中,堪称事半功倍的绝佳选择。
3、parallel:比 xargs 更强的 “多线程执行工具”,支持任务分发
核心能力:能够依据 CPU 核心数量自动分配并行任务,还支持 “远程执行” 模式,可借助 SSH 将任务高效分发给多台机器。与 xargs 的 -P 参数相比,它展现出更高的灵活性,例如能够显示任务进度,并且支持错误重试机制。
实战场景:在本地机器上,需对 “/data/backup” 目录下的 10 个.tar.gz 备份文件进行并行解压。若采用单线程解压,每个文件解压耗时约 5 分钟,完成全部 10 个文件解压则需 50 分钟;而使用 4 线程并行解压,仅需 15 分钟即可大功告成。
代码示例:
# 安装parallel(CentOS:yum install parallel;Ubuntu:apt install parallel)
# 查找.tar.gz文件,并行解压(-j 4指定4个线程,--bar显示进度条)
find /data/backup -name "*.tar.gz" | parallel -j 4 --bar "tar zxf {} -C /data/restore"
# --bar:显示每个任务的进度条,便于精准监控执行状态
4、trap:宛如捕获信号的 “安全屏障”,能有效防止脚本意外退出而造成数据损坏。
核心能力:可以捕获 Linux 系统中的各类信号,例如按下 Ctrl + C 时产生的 SIGINT 信号,以及脚本被 kill 时的 SIGTERM 信号等。并且,它能够执行自定义的清理逻辑,诸如删除临时文件、关闭数据库连接等操作。
实战场景:编写一个 “数据库备份脚本”,当脚本在执行过程中意外终止(例如用户按下 Ctrl + C),该脚本能够自动删除未完成的临时备份文件,从而避免残留的无效文件占用系统空间。
代码示例:
#!/bin/bash
set -e
# 定义临时备份文件路径
TMP_BACKUP="/tmp/db_backup_$(date +%Y%m%d).sql"
# 1. 捕获SIGINT(2)、SIGTERM(15)信号,执行清理函数
trap 'cleanup' 2 15
cleanup() {
echo -e "
脚本被终止,开始清理临时文件..."
if [ -f "$TMP_BACKUP" ]; then
rm -f "$TMP_BACKUP" # 删除未完成的临时备份
echo "临时文件 $TMP_BACKUP 已删除"
fi
exit 1
}
# 2. 执行数据库备份(假设用mysqldump备份MySQL)
echo "开始备份数据库到 $TMP_BACKUP..."
mysqldump -u root -p"123456" --databases testdb > "$TMP_BACKUP"
# 3. 备份完成后,将临时文件移动到正式备份目录(/data/backup)
mv "$TMP_BACKUP" /data/backup/
echo "备份完成,正式文件路径:/data/backup/$(basename $TMP_BACKUP)"
关键要点:trap 指令必须放置在脚本的起始位置,以此确保在所有操作执行之前,先完成信号捕获的注册。这样做能够避免出现 “先执行备份操作,之后才进行信号捕获注册,导致脚本在中途被终止时无法触发清理逻辑” 的情况。
5、expect:堪称自动化交互领域的 “智能机器人”,专门用于应对 “需要手动输入密码” 这类应用场景。
核心能力:能够模拟人工交互行为,像输入密码、确认操作等,还可以自动响应命令所产生的交互提示,例如在进行 ssh 登录时出现的 “Are you sure you want to continue connecting?” 提示,以及使用 sudo 时的密码提示等。
实战场景:借助 SSH 对 10 台服务器进行批量登录,并执行 “查看磁盘使用率” 的命令,在此过程中无需手动逐台输入服务器的 SSH 密码。
代码示例:
#!/usr/bin/expect
# 注意:expect脚本解释器是expect,不是bash
set timeout 10
# 超时时间(秒),避免连接卡住
set host_list "192.168.1.101 192.168.1.102 192.168.1.103"
# 服务器列表
set username "root"
# SSH用户名
set password "123456"
# SSH密码(生产环境提议用密钥登录,避免明文密码)
# 遍历服务器列表
foreach host $host_list {
spawn ssh $username@$host
# 启动ssh进程
expect {
"Are you sure you want to continue connecting" {
# 首次登录提示
send "yes
"
exp_continue
# 继续等待后续提示
}
"password:" {
# 密码提示
send "$password
"
}
}
# 登录后执行命令:查看磁盘使用率(df -h),执行完退出
expect "$ " {
# 等待命令行提示符(如root@host:~#)
send "df -h
"
expect "$ " {
send "exit
"
}
}
wait
# 等待当前服务器操作完成,再处理下一台
puts "===== 服务器 $host 操作完成 ====="
}
生产环境注意事项:为保障安全性,应避免以明文形式书写密码,提议改用 SSH 密钥登录。具体操作是使用 ssh – keygen 生成密钥,再通过 ssh – copy – id 将密钥分发到目标服务器。采用这种方式后,expect 便无需再处理密码相关问题,从而显著提升系统的安全性。
6、bc:作为高精度计算的 “专业计算器”,有效突破了 Shell 整数计算的局限。
核心能力:它支持浮点数计算以及各类数学函数,像平方根、三角函数等,成功弥补了 Shell 原生仅能进行整数计算的短板。例如,使用 “echo ‘2/3’ | bc -l” 可输出 0.666666…,而 “$((2/3))” 只能输出 0。
实战场景:编写一个 “系统资源监控脚本”,用于计算 “内存使用率”。内存使用率的计算公式为(总内存 – 空闲内存)/ 总内存 * 100%,且计算结果需保留 2 位小数。
代码示例:
#!/bin/bash
# 从/proc/meminfo中提取总内存(MemTotal)和空闲内存(MemFree+Buffers+Cached)
mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
mem_free=$(grep -E "MemFree|Buffers|Cached" /proc/meminfo | awk '{sum+=$2} END {print sum}')
# 用bc计算内存使用率(-l启用浮点数计算,scale=2保留2位小数)
mem_usage=$(echo "scale=2; ($mem_total - $mem_free)/$mem_total * 100" | bc)
echo "当前内存使用率:$mem_usage%"
# 若使用率超过80%,发送告警(如邮件、企业微信机器人)
if (( $(echo "$mem_usage > 80" | bc -l) )); then
echo "警告:内存使用率超过80%,请及时处理!"
# 此处可加告警逻辑,如调用企业微信机器人API
fi
7、find + exec:作为一套较 xargs 更为灵活的 “批量处理组合拳”,具备条件判断功能。
核心能力:借助 find 命令查找文件,-exec 可直接执行命令,无需通过管道,支持对每个文件执行多步操作。此外,还能通过 -ok 实现 “交互确认”,即在执行操作前询问用户意见。
实战场景:在 “/var/www/html” 目录下,查找那些 “权限为 777 且文件大小大于 100KB” 的.php 文件。先输出这些文件的路径,随后将其权限修改为 755,以此避免因高权限设置引发安全风险。
代码示例:
# -perm 777:权限为777;-size +100k:文件大小大于100KB;-type f:普通文件
find /var/www/html -type f -name "*.php" -perm 777 -size +100k -exec sh -c '
echo "处理高权限文件:$1"
# $1是find传递的文件路径
chmod 755 "$1"
# 将权限改为755(所有者读/写/执行,其他读/执行)
' sh {} ;
# sh {}:将find的每个文件路径作为参数传递给sh脚本
进阶用法:使用 -ok 替换 -exec(即 find … -ok chmod 755 {} ;),执行前会弹出询问 “是否执行 chmod…?”,此方式适用于需要人工确认的场景。
8、sshpass:一款免交互的 SSH 登录工具,在自动化运维场景中具有必定的适用性,但非生产环境使用时需谨慎对待。
核心能力:能够通过命令行参数传递 SSH 密码,从而避免手动输入密码的繁琐操作,尤其适用于 “非生产环境的自动化登录”。不过,在生产环境中,提议采用密钥登录的方式,以防止密码泄露带来的安全风险。
实战场景:对 10 台测试服务器进行批量检查,确认 “Nginx 服务状态”,若服务未运行则启动该服务。
代码示例:
#!/bin/bash
# 服务器列表(IP:密码,非生产环境临时使用)
hosts=("192.168.1.101:123456" "192.168.1.102:123456")
for host in "${hosts[@]}"; do
# 拆分IP和密码(以:为分隔符)
ip=${host%%:*}
pwd=${host#*:}
echo "===== 检查服务器 $ip 的Nginx状态 ====="
# 用sshpass登录,执行命令:检查Nginx是否运行,未运行则启动
sshpass -p "$pwd" ssh -o StrictHostKeyChecking=no $ip '
if systemctl is-active --quiet nginx; then
echo "Nginx已运行"
else
echo "Nginx未运行,开始启动..."
systemctl start nginx
# 启动后再次检查状态
if systemctl is-active --quiet nginx; then
echo "Nginx启动成功"
else
echo "警告:Nginx启动失败"
fi
fi
'
done
注意事项:
- -o StrictHostKeyChecking=no 这一参数用于在首次登录时不提示 “是否信任主机” 的询问,适合自动化操作。
- 在生产环境中,应禁用 sshpass,提议使用 ssh – keygen 生成密钥,并通过 ssh – copy – id 将密钥分发到目标服务器,实现无密码登录,以保障系统的安全性。
9、diff + patch:作为文件对比与补丁生成的专业工具,在多环境配置同步方面表现卓越。
核心能力:diff 能够精准对比两个文件之间的差异,并生成 “补丁文件”;而 patch 则可利用该补丁文件对目标文件进行更新,从而避免了手动修改配置的繁琐与易错性。以多台服务器的 Nginx 配置同步为例,只需生成一个补丁文件,便可以进行批量应用。
实战场景:在本地对 Nginx 配置文件(/etc/nginx/nginx.conf)进行修改后,生成补丁文件,并将该补丁应用到远程服务器的一样文件中。
代码示例:
# 1. 本地生成补丁:对比修改前的配置(nginx.conf.old)和修改后的配置(nginx.conf)
diff -u nginx.conf.old nginx.conf > nginx.conf.patch
# -u:生成“统一格式”补丁,包含上下文,更易阅读和修复
# 2. 将补丁文件上传到远程服务器(假设IP为192.168.1.100,路径为/tmp)
scp nginx.conf.patch root@192.168.1.100:/tmp/
# 3. 远程登录服务器,应用补丁(-p1:忽略补丁中的路径前缀,直接对当前文件操作)
ssh root@192.168.1.100 "cd /etc/nginx && patch -p1 < /tmp/nginx.conf.patch"
# 4. 应用后重启Nginx,验证配置是否生效
ssh root@192.168.1.100 "nginx -t && systemctl restart nginx"
优势:相较于 “直接覆盖配置文件” 的方式,patch 仅对文件的差异部分进行修改,有效避免了覆盖服务器上其他自定义配置的风险,大大提升了操作的安全性。
10、ps + awk + kill:堪称进程管理领域的精妙组合拳,可用于批量终结 “僵尸进程” 或者 “占用过高资源的进程”。
核心能力:借助 ps 命令查看进程的详细信息,利用 awk 对目标进程进行精准筛选(例如筛选出 CPU 使用率超过 90% 的进程),再通过 kill 命令终止进程。这一组合十分契合系统运维中的 “进程清理” 场景。
实战场景:查找那些 “CPU 使用率超过 90% 且运行时间超过 1 小时” 的 Java 进程,先输出这些进程的详细信息,随后进行批量终止操作,以此避免因过多占用 CPU 资源导致系统出现卡顿现象。
代码示例:
#!/bin/bash
# 1. ps获取进程信息(-eo:自定义输出字段,%cpu:CPU使用率,etime:运行时间,cmd:命令)
# 2. awk筛选:CPU>90%、命令含java、运行时间>1小时(etime格式如1-02:30:00代表1天2小时30分,或3600代表3600秒)
# 3. 提取PID(第2列),传递给kill
ps -eo pid,%cpu,etime,cmd | awk '$2 > 90 && $4 ~ /java/ {
# 判断运行时间:若etime含"-"(天),直接满足;若不含,转成秒判断是否>3600(1小时)
split($3, t, /[:-]/)
if (length(t) == 5) { # 格式:HH:MM:SS,转成秒:H
注:你提供的代码似乎未完整,若你需要我对完整代码进行润色或有其他需求,请补充完整后继续向我提问。

收藏了,感谢分享