一、Shell 脚本基础
1. 脚本概念与应用场景
核心概念
Shell 脚本是将一系列 Linux 命令按执行顺序保存在.sh后缀的文件中,赋予执行权限后,配合分支、循环等控制语句,实现批量、自动化处理的脚本程序。
典型应用场景
- 服务批量部署
- 系统状态监控
- 定时数据备份
- 日常自动化运维
2. 脚本结构与执行方式
标准脚本结构
bash
#!/bin/bash # 注释:脚本功能、版本、作者说明 # 以下为具体执行的命令 echo "Hello Shell Script"#!/bin/bash:声明脚本解析器,指定用 bash 解释执行,必须写在文件第一行#:单行注释,脚本执行时会忽略注释内容
4 种执行方式
bash
# 方式1:解释器直接执行(无需执行权限,开启子Shell运行) sh test.sh bash test.sh # 方式2:路径执行(需先赋予执行权限 chmod +x test.sh) ./test.sh # 相对路径执行 /root/test.sh # 绝对路径执行 # 方式3:点号执行(当前Shell环境执行,变量会生效) . test.sh # 方式4:source执行(同点号,当前Shell加载变量) source test.sh注释:方式 3、4 会将脚本内变量加载到当前终端环境;方式 1、2 在子 Shell 中运行,不影响当前环境变量。
语法检测命令
bash
sh -n test.sh # 作用:仅检查脚本语法错误,不实际执行脚本3. 输入输出与重定向
基础输入输出
bash
# 输出命令 echo "这是一行输出内容" # 输入命令:读取用户输入并赋值给变量 read -p "请输入用户名:" username echo "欢迎你,$username" # -p:指定输入前的提示文字重定向符号
表格
| 符号 | 类型 | 作用说明 |
|---|---|---|
> | 覆盖输出重定向 | 将命令正确输出写入文件,覆盖原有内容 |
>> | 追加输出重定向 | 将命令正确输出追加到文件末尾 |
2> | 错误输出重定向 | 将命令报错信息写入文件 |
&> | 全量输出重定向 | 正确输出 + 错误输出统一写入文件 |
< | 输入重定向 | 将文件内容作为命令的输入对象 |
bash
# 示例:覆盖写入文件 echo "测试内容" > a.txt # 示例:错误日志收集 ls /不存在的路径 2> error.log # 示例:here文档批量写入文件 cat > test.txt << EOF 第一行内容 第二行内容 第三行内容 EOF # 注释:EOF为自定义分界符,遇到相同分界符结束输入 # 若分界符加单引号 'EOF',则不解析变量,所见即所得4. 变量体系
变量定义规则
- 格式:
变量名=变量值,等号两侧绝对不能有空格 - 变量名只能由字母、数字、下划线组成,不能以数字开头
变量分类与用法
(1)自定义变量
bash
# 定义变量 name="zhangsan" age=22 # 调用变量:$变量名 或 ${变量名}(推荐加{}避免歧义) echo $name echo "年龄:${age}岁"(2)三种引号的区别
bash
name="tom" # 单引号:强引用,所见即所得,不解析任何变量和特殊符号 echo '名字是$name' # 输出:名字是$name # 双引号:弱引用,可以解析变量 echo "名字是$name" # 输出:名字是tom # 不加引号:解析所有特殊符号,支持通配、命令替换 echo $name $age(3)系统环境变量
操作系统预定义的全局变量,常用示例:
bash
echo $PATH # 命令搜索路径 echo $HOME # 当前用户家目录 echo $USER # 当前用户名 echo $HOSTNAME # 主机名(4)全局变量与局部变量
- 全局变量:整个 Shell 环境都可访问
- 局部变量:仅函数 / 脚本内部有效,用
local关键字声明
(5)位置变量
执行脚本时,向脚本内部传递的参数
bash
# 脚本内写法(test.sh) echo "脚本名称:$0" echo "第1个参数:$1" echo "第2个参数:$2" echo "第10个参数:${10}" # 超过9个参数必须加{} # 执行命令:sh test.sh apple banana orange # 输出对应参数值(6)预定义变量
Shell 内置固定含义的特殊变量
表格
| 变量 | 含义说明 |
|---|---|
$# | 统计传入脚本的参数总个数 |
$* | 列出所有参数,整体作为一个字符串 |
$@ | 列出所有参数,每个参数为独立个体 |
$$ | 获取当前脚本的进程号 PID |
$? | 上一条命令的执行返回值,0 = 成功,非 0 = 失败 |
bash
# 示例脚本 echo "参数总数:$#" echo "全部参数:$@" echo "进程PID:$$"5. 算术运算
Shell 默认不支持直接数学运算,需通过特定方式实现。
常用运算符
+加、-减、*乘、/除、%取余(取模)
4 种运算实现方式
bash
a=10 b=3 # 方式1:expr 命令 # 注意:运算符两侧必须有空格,乘号需要转义 \* result=`expr $a + $b` echo $result # 输出13 # 方式2:let 命令 let sum=$a+$b echo $sum # 方式3:双括号 (( )) (最常用写法) echo $((a*b)) # 输出30 echo $((a%b)) # 输出1 # 方式4:bc 命令(唯一支持小数运算) echo "scale=2; 10/3" | bc # scale=2 表示保留2位小数6. 条件判断
(1)文件 / 目录判断
表格
| 选项 | 作用说明 |
|---|---|
-d | 判断目标是否为目录 / 目录是否存在 |
-f | 判断目标是否为文件 / 文件是否存在 |
-e | 判断目标是否存在(文件、目录通用) |
-r | 判断文件是否可读 |
-w | 判断文件是否可写 |
-x | 判断文件是否可执行 |
bash
# 示例:判断/root是否为目录 [ -d /root ] && echo "是目录" || echo "不是目录" # 注释:中括号 [] 两侧必须有空格(2)整数比较运算符
表格
| 选项 | 英文全称 | 含义 |
|---|---|---|
-gt | greater than | 大于 |
-lt | less than | 小于 |
-eq | equal | 等于 |
-ge | greater equal | 大于等于 |
-le | less equal | 小于等于 |
-ne | not equal | 不等于 |
bash
# 示例:判断10是否大于5 [ 10 -gt 5 ] && echo "大于"(3)逻辑运算符
表格
| 符号 | 含义 | 使用场景 | |
|---|---|---|---|
-a | 并且(and) | 写在单个 [] 内部 | |
-o | 或者(or) | 写在单个 [] 内部 | |
&& | 并且 | 连接两个命令 / 判断,前成功才执行后 | |
| ` | ` | 或者 | 连接两个命令 / 判断,前失败才执行后 |
! | 非(取反) | 条件取反 |
bash
# 示例:多条件并列判断 age=25 [ $age -gt 18 -a $age -lt 30 ] && echo "青年"7. 流程控制:if 分支语句
单分支结构
bash
if 条件;then 条件成立时执行的命令 fibash
# 示例:判断文件是否存在 if [ -f test.txt ];then echo "文件存在" fi双分支结构
bash
if 条件;then 条件成立执行 else 条件不成立执行 fibash
# 示例:数字大小判断 num=15 if [ $num -gt 10 ];then echo "数字大于10" else echo "数字小于等于10" fi多分支结构
bash
if 条件1;then 条件1成立执行 elif 条件2;then 条件2成立执行 elif 条件3;then 条件3成立执行 else 所有条件都不成立时执行 fibash
# 示例:体重分级判断 weight=85 if [ $weight -ge 100 ];then echo "过重" elif [ $weight -ge 90 ];then echo "有点胖" elif [ $weight -ge 80 ];then echo "黄金身材" else echo "太瘦" fi注释:if 判断具有阻塞性,匹配到第一个符合条件的分支后,不再向下判断后续条件。
8. 流程控制:for 循环
基础语法
bash
for 变量 in 取值范围 do 循环体命令 done4 种取值方式
bash
# 方式1:列举式取值 for i in apple banana orange do echo "水果:$i" done # 方式2:序列式 {} for i in {1..10} # 生成1到10的整数序列 do echo $i done # 方式3:命令结果取值 for user in `cat /etc/passwd | head -5` do echo $user done # 方式4:C语言风格 for ((i=1; i<=10; i++)) do echo "第$i次循环" done9. 流程控制:while 循环
基础语法
bash
while 循环条件 do 循环体命令 done两大常用场景
bash
# 场景1:按行读取文件内容 while read line do echo "行内容:$line" done < test.txt # 场景2:死循环 while : do echo "死循环运行中,按Ctrl+C停止" sleep 1 done # 等价写法:while true; do ... done10. 流程控制:case 多分支语句
语法格式
bash
case $变量名 in 匹配模式1) 模式1对应的执行命令 ;; 匹配模式2) 模式2对应的执行命令 ;; *) 所有模式都不匹配时执行 ;; esacbash
# 示例:简易选择菜单 read -p "请输入数字(1-3): " num case $num in 1) echo "你选择了选项1" ;; 2) echo "你选择了选项2" ;; 3) echo "你选择了选项3" ;; *) echo "输入错误,请输入1-3" ;; esac注释:每个分支结尾必须写
;;代表跳出 case;*是通配符,匹配所有情况。
二、sed 文本处理工具
1. 基础介绍
sed 是流式编辑器,核心能力是对文本进行增、删、改、查,支持正则匹配,可直接修改源文件。
基础语法
bash
sed [选项] '处理动作' 文件名常用选项
表格
| 选项 | 作用说明 |
|---|---|
-n | 取消默认全量输出,只输出匹配处理的行 |
-i | 直接修改源文件(不加 - i 仅在内存修改,不影响原文件) |
-e | 支持同时执行多个编辑指令 |
-r | 开启扩展正则表达式支持 |
2. 核心四大操作
(1)查(打印 p)
bash
# 打印第3行 sed -n '3p' test.txt # 打印第2到第5行 sed -n '2,5p' test.txt # 打印第2行和第5行 sed -n '2p;5p' test.txt # 打印包含字符串"root"的行 sed -n '/root/p' test.txt(2)增(a 追加 /i 插入)
a:在指定行后面追加内容i:在指定行前面插入内容
bash
# 在第2行后面追加一行内容 sed '2a 这是追加的新内容' test.txt # 在包含"hello"的行前面插入内容 sed '/hello/i 插入的内容' test.txt # 给每一行行首添加#注释 sed 's/^/#/' test.txt # 给每一行行尾添加注释标记 sed 's/$/ #注释/' test.txt(3)删(删除 d)
bash
# 删除第3行 sed '3d' test.txt # 删除第2到第4行 sed '2,4d' test.txt # 删除包含"error"的行 sed '/error/d' test.txt # 删除所有空行 sed '/^$/d' test.txt(4)改(c 整行替换 /s 字符串替换)
c:整行内容替换s:行内字符串替换
bash
# 整行替换:第3行替换为全新内容 sed '3c 全新的行内容' test.txt # 替换每行第一个old为new sed 's/old/new/' test.txt # 全局替换:替换所有old为new sed 's/old/new/g' test.txt # 只替换第3到第5行内的old sed '3,5s/old/new/g' test.txt注释:替换语法
s#原内容#新内容#g中,分隔符可用/#@等,内容含/时推荐用#避免转义。
3. 分组与反向引用
用()对内容分组,通过\1 \2反向引用分组匹配的内容
bash
# 示例:提取网卡IP地址 ip a | sed -n '9p' | sed -r 's#(.*)inet (.*)/24 (.*)#\2#' # 注释: # -r 开启扩展正则,支持()分组 # \2 引用第二个括号匹配到的内容,即IP地址部分4. 实战:抓取本机 IP 地址
bash
# 方法1:sed纯提取 ip a | sed -n '/inet /p' | sed -r 's#.*inet (.*)/24.*#\1#' | grep -v 127.0.0.1 # 方法2:grep+正则配合 ip a | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -Ev "127|255"三、awk 文本处理工具
1. 基础介绍
awk 是强大的结构化文本处理工具,支持横向按行过滤、纵向按列提取,尤其适合处理表格类、分隔符类文本。
四种语法格式
bash
# 格式1:基础格式 awk '模式{动作}' 文件名 # 格式2:指定列分隔符 awk -F "分隔符" '模式{动作}' 文件名 # 格式3:指定多个分隔符(贪婪匹配) awk -F "[分隔符集合]+" '模式{动作}' 文件名 # + 表示贪婪模式,多个连续分隔符视为一个 # 格式4:完整三段式 awk -F "分隔符" 'BEGIN{初始化动作} 模式{逐行动作} END{收尾动作}' 文件名BEGIN{}:处理文件前执行,仅执行 1 次,常用于设置变量、打印表头- 中间
模式{动作}:逐行处理,每行执行一次 END{}:所有行处理完后执行,仅执行 1 次,常用于统计、输出总结
2. 内置变量
表格
| 变量 | 含义说明 |
|---|---|
NR | 行号(Number of Record),当前处理的是第几行 |
NF | 列数(Number of Field),当前行总列数 |
$n | 第 n 列内容,$1第一列,$NF代表最后一列 |
FS | 输入列分隔符,作用同 - F,优先级高于 - F |
OFS | 输出列分隔符 |
RS | 输入行分隔符,默认换行符 |
ORS | 输出行分隔符,默认换行符 |
bash
# 示例:打印行号和第一列内容 awk '{print NR, $1}' test.txt # 示例:冒号分隔,打印用户名和登录shell awk -F ":" '{print $1, $NF}' /etc/passwd # 示例:生成CSV格式表格 awk -F "[:/ ]+" 'BEGIN{print "name,bash"}{print $1","$NF}' 1.txt > 6.csv # 注释:BEGIN先输出表头,逐行输出内容,最终重定向为csv文件3. 模式(匹配条件)
(1)行号比较表达式
bash
# 打印第3行 awk 'NR==3{print}' test.txt # 打印第2到第5行 awk 'NR>=2 && NR<=5{print}' test.txt # 打印第2行之前和第5行之后 awk 'NR<2 || NR>5{print}' test.txt(2)正则表达式匹配
表格
| 正则写法 | 含义说明 |
|---|---|
/^字符/ | 匹配以指定字符开头的行 |
/字符$/ | 匹配以指定字符结尾的行 |
/./ | 匹配任意一个字符 |
/?/ | 匹配前一个字符 0 次或 1 次 |
/+/ | 匹配前一个字符 1 次及以上 |
$n~/正则/ | 指定第 n 列匹配正则 |
bash
# 匹配以root开头的行 awk '/^root/' /etc/passwd # 匹配第三列以41开头的行 awk -F ":" '$3~/^41/' /etc/passwd4. 实战练习题(捐款数据场景)
测试数据说明(reg.txt): 第 1 列 = 姓氏,第 2 列 = 名字,第 3 列 = ID 号码,第 4/5/6 列 = 三次捐款金额
题 1:显示姓 Zhang 的人的第二次捐款金额及姓名
bash
awk -F "[ :]+" '/Zhang/{print $1$2, $5}' reg.txt # 注释:分隔符为空格+冒号,$1$2拼接全名,$5是第二次捐款题 2:显示 Xiaoyu 的名字和 ID 号码
bash
awk -F "[ :]+" '$2~/Xiaoyu/{print $1$2, $3}' reg.txt # 注释:$2~/Xiaoyu/ 精确匹配第二列为Xiaoyu的行题 3:显示所有以 41 开头的 ID 对应的全名和 ID
bash
awk -F "[ :]+" '$3~/^41/{print $1$2, $3}' reg.txt # ^41 表示字符串以41开头题 4:显示所有以 D 或 X 开头的人名全名
bash
awk -F "[ :]+" '$2~/^D|^X/{print $1$2}' reg.txt # ^D|^X 匹配以D开头 或以X开头题 5:显示 ID 最后一位是 1 或 5 的人的全名
bash
awk -F "[ :]+" '$3~/[15]$/{print $1$2}' reg.txt # [15]$ 表示以1或5结尾题 6:显示 Xiaoyu 的捐款,每个金额前加 $ 符号
bash
awk -F "[ :]+" '$2~/Xiaoyu/{print "$"$4, "$"$5, "$"$6}' reg.txt题 7:显示所有人全名,格式为 姓,名
bash
awk -F "[ :]+" '{print $1","$2}' reg.txt5. awk 数组基础
awk 中的数组本质是键值对集合,元素具有天然唯一性,常用于去重、统计次数。
bash
# 基础示例:数组赋值与取值 awk 'BEGIN{ arr[0]="apple" arr[1]="banana" print arr[0] }'特性:数组下标可以是数字也可以是字符串;元素不重复,典型应用为日志 IP 去重、访问次数统计。