Shell 脚本与三剑客实战(写脚本 + grep/sed/awk 处理文本)

分类:Shell脚本与三剑客
标签: Shell、脚本、grep、sed、awk、正则、管道
摘要: 日常运维很多重复操作,写个脚本一次跑完。本文从”脚本怎么搭骨架”讲到”怎么批量处理文本”,把 shell 语法和三剑客 grep / sed / awk 一起讲透,含正则地基地和一条流水线的实战。


一、脚本的骨架(三步固定)

#!/bin/bash        # 第1行,声明用 bash 解释
chmod +x 脚本.sh   # 第2步,加执行权限
./脚本.sh           # 第3步,运行(或用 bash 脚本.sh)

变量 / 输入:

name="zhu"         # 定义变量(= 两边不能有空格!)
echo $name         # 用变量
read var           # 让用户输入

位置参数(传参):

./a.sh hello world
# $0=脚本名  $1=hello  $2=world  $#=参数个数  $@=所有参数

引号区别(常考):

'单引号'   # 是啥就是啥,不解析变量
"双引号"   # 会解析里面的 $变量
`反引号`    # 执行命令取结果(等价 $( ))

二、逻辑三件套:if / for / case

if [ $a -eq $b ]; then
   echo "相等"
else
   echo "不等"
fi
# 数字比较:-eq等 -ne不等 -gt大于 -lt小于 -ge≥ -le≤
# 文件判断:-e存在 -f是文件 -d是目录
# 逻辑组合:&&和  ||或  !非
for i in 1 2 3; do echo $i; done      # 固定次数循环
while [ 条件 ]; do ...; done           # 条件循环
case $1 in          # 多分支(类似 switch)
  start) echo "启动";;
  stop)  echo "停止";;
  *)     echo "未知";;
esac

函数 & 必背技巧:

myfunc() { echo "这是函数"; }
myfunc                             # 调用
$?        # 上一条命令成功否(0=成功)★排障常看
$(命令)    # 命令结果当值用:echo "今天 $(date)"
> 覆盖写    >> 追加写    2> 错误输出    | 管道
exit 0    # 脚本退出码

三、正则基础(三剑客的地基,先看这个)

^     行开头       ^a    以a开头
$     行结尾       b$    以b结尾
.     任意一个字符
[]    集合         [abc]=a或b或c;[0-9]=数字;[a-z]=小写字母
[^]   排除         [^0-9]=非数字
*     前一个出现0次或多    ab* → a,ab,abb
+     前一个出现1次或多(需-E)ab+ → ab,abb
?     前一个0次或1次(需-E)ab? → a,ab
|     或(需-E)   a|b → a 或 b
{n}   出现n次      a{2} → aa

四、三剑客分工(一句话记牢)

grep 负责”找行”,sed 负责”改行”,awk 负责”取列/统计”。

grep —— 找内容 / 过滤

grep 关键词 文件           # 基本搜索
grep -i 关键词 文件         # 忽略大小写
grep -n 关键词 文件         # 带行号
grep -c 关键词 文件         # 只返回命中行数
grep -v 关键词 文件         # 取反:不含关键词的行
grep -r 关键词 目录/        # 递归搜整个目录
grep -E "a|b" 文件         # 扩展正则(用 | + 等)
grep -A2 "关键词" 文件      # 匹配行 + 后面2行(看上下文)
# 实战:看 nginx 报错
grep -i error /var/log/nginx/error.log | tail

sed —— 替换 / 删行

sed 's/旧/新/' 文件       # 每行替换第一个匹配
sed 's/旧/新/g' 文件      # 全局替换(g=global)
sed -i 's/旧/新/g' 文件   # -i 就地直接改文件 ★改前先预览
sed -n '3,5p' 文件       # 只打印第3~5行
sed '1,5d' 文件           # 删第1~5行
# 稳妥三步:先看效果 → 再 -i 落盘
sed 's/8080/8081/g' nginx.conf           # 预览
sed -i 's/8080/8081/g' nginx.conf        # 确认后才改

awk —— 按列处理 / 统计

awk '{print $1}' 文件        # 取第1列(默认按空白分列)
awk -F: '{print $1}' /etc/passwd   # -F 指定分隔符(按 : 分)
awk '{print NR, $0}' 文件    # NR=行号,$0=整行
awk '$3 > 50 {print}' 文件   # 条件:第3列>50才打印
awk '{s+=$1} END{print s}' 文件   # 第1列求和
awk 'END{print NR}' 文件     # 统计总行数
# ★明星案例:统计访问日志 IP 次数并降序
awk '{print $1}' access.log | sort | uniq -c | sort -rn
#   取IP列 → 排序 → 去重计数 → 按次数降序

五、三剑客配合管道(最常用的一条流水线)

# 读日志→过滤含blog→取IP列→计数→降序→看前10
cat access.log | grep blog | awk '{print $1}' | sort | uniq -c | sort -rn | head

六、踩坑速记

坑现象解决
变量赋值报错command not found= 两边不能有空格
中文乱码/引号结果不对用英文半角引号 ' "
sed 改完发现错了文件被改坏先预览,重要文件 cp 备份
正则不生效+ ? | 没效果加 -E 用扩展正则
脚本不执行Permission deniedchmod +x 脚本