一、Shell 基础概述
1. Shell 发展历史
-
1964 年:贝尔实验室、MIT、通用电气联合研发
Multics大型多用户系统 -
1970 年:丹尼斯・里奇、汤普逊启动
UNICS项目,后续演进为 Unix -
1973 年:使用 C 语言重写 Unix,实现跨机型移植
-
1979 年:首个标准 Bourne Shell(sh) 正式发布
-
后续衍生:
csh/tcsh/ksh/bash/zsh,Linux 默认 Shell 为 bash
2. 查看系统 Shell
bash
# 查看系统所有支持的Shell
cat /etc/shells
# 查看当前登录默认Shell
echo $SHELL
3. Shell 两大核心定位
-
命令解释器 用户操作 → Shell 解析命令 → 传递内核 → 调度硬件; Shell 是用户与 Linux 内核的中间代理,不属于内核,是独立应用程序。
-
解释型脚本语言
-
无需编译,直接运行源码,开发部署极简
-
内置两千 + Linux 命令,搭配三剑客可做系统自动化运维
-
对比编译型语言:脚本灵活跨平台;编译型速度快、保密性强
二、Shell 脚本书写规范与执行
1. 标准书写规范
-
脚本后缀建议:
.sh,见名知意 -
首行固定声明解析器:
#!/bin/bash -
注释规则
-
单行注释:
#开头 -
多行注释语法:
bash
:<<'EOF'
这里是多行注释第一行
这里是多行注释第二行
EOF
- 可配置
~/.vimrc新建.sh 自动生成头部版权注释
2. 常用输出命令
echo 命令
-
-n:不换行输出 -
-e:启用转义字符,可设置字体颜色、高亮、下划线
printf 命令
-
格式化输出,必须手动加
\n换行 -
支持格式符:
%s字符串、%d整型、%f浮点 -
可设置字符宽度、左右对齐、保留小数位数
3. 一行多命令连接符
|------|---------------|
| 符号 | 功能说明 |
| ; | 顺序执行,前后命令互不影响 |
| & | &前命令成功才执行后命令 |
| || | 前命令失败才执行后命令 |
| | | 管道,左输出作为右输入 |
4. 脚本四种执行方式
-
绝对路径 / 相对路径 :需
x执行权限,子 Shell 运行,不影响当前终端 -
bash 脚本名:无需执行权限,子 Shell 运行
-
source 脚本名:当前 Shell 运行,变量 / 目录切换永久生效
-
. 脚本名:等同于 source
核心区别:子 Shell 执行不影响当前环境;source/. 在当前 Shell 执行,环境变更永久生效。
5. 退出状态码
-
范围:
0~255,0 成功,非 0 失败 -
查看状态码:
echo $? -
脚本自定义退出:
exit 数字 -
函数返回状态码:
return 数字 -
常见状态码:
-
0:命令执行成功
-
1:未知错误
-
2:命令使用错误
-
126:命令不可执行
-
127:命令未找到
-
130:Ctrl+C 强制终止
三、Shell 变量全解
1. 变量命名与赋值规则
-
命名:只能字母、数字、下划线,不能数字开头
-
赋值:
变量=值,等号两边严禁空格 -
值含空格必须用单 / 双引号包裹
-
Shell 是弱类型动态语言,所有变量均以字符串存储
2. 变量定义方式
-
临时变量:命令行直接定义,退出终端失效
-
命令赋值:\
\var=date``` 或var=$(date)` -
交互式赋值:
read -p "提示信息" 变量1 变量2 -
永久环境变量
-
用户级:
~/.bashrc、~/.bash_profile -
系统级:
/etc/profile、/etc/bashrc、/etc/profile.d/*.sh
-
3. 特殊位置参数变量
|--------|----------------|
| 变量 | 含义 |
| 0 | 脚本自身名称 |
| 19 | 第 1 到第 9 个位置参数 |
| {10} | 10 个以上参数必须加大括号 |
| \* | 所有参数视为一个整体 |
| @ | 所有参数独立分开 |
| # | 传入参数总个数 |
| \\$$ | 当前脚本进程 PID |
| ? | 上一条命令退出状态码 |
4. 引号与特殊符号区别
-
单引号
'':所有符号原样输出,无任何解析 -
双引号
"":解析$、`````、\,其余字符原样 -
反引号 `````:将内容当作系统命令执行
-
反斜线
\:转义特殊字符,取消特殊含义
5. 变量运算
-
整数运算:
$(( ))、$[]、let、expr -
小数运算:仅
bc、awk支持 -
字符串处理语法
bash${#var} # 获取字符串长度 ${var:start:len} # 字符串截取 ${var/old/new} # 替换第一个匹配 ${var//old/new} # 全局替换 ${var#*.} # 从左最短删除 ${var##*.} # 从左最长删除 ${var%.*} # 从右最短删除 ${var%%.*} # 从右最长删除
6. 变量作用域
- 局部变量
-
普通变量:当前脚本 / 终端生效
-
函数局部:
local 变量仅函数内部有效
- 全局环境变量
-
定义:
export 变量=值 -
特性:当前 Shell 及所有子进程共享
7. 变量默认值扩展语法
|--------------|------------------|--------|
| 语法 | 作用 | 是否修改变量 |
| {var:-word} | 变量为空返回 word,原值不变 | 否 |
| {var:=word} | 变量为空赋值为 word | 是 |
| {var:+word} | 变量非空返回 word | 否 |
| {var:?word} | 变量为空抛出错误并退出 | 否 |
8. 经典案例
-
两数加减乘除、求余
-
1~100 求和、奇数和、偶数和
-
批量批量重命名文件
-
自动清理 7 天前过期备份
四、条件测试
1. 四种测试语法
-
test 条件表达式 -
[ 条件表达式 ]「中括号左右必须有空格」 -
[[ 条件表达式 ]]支持正则、逻辑更强大 -
(( 整数表达式 ))仅用于整数判断
2. 三大测试类型
文件测试
-e存在、-d目录、-f普通文件、-L软链接、-r可读、-w可写、-x可执行、-nt文件更新、-ot文件更旧
字符串测试
-z空字符串、-n非空字符串、=相等、!=不等
整数测试
-
[]/test使用:-eq -ne -gt -ge -lt -le -
[[]]/(())直接使用:> < >= <= == !=
3. 逻辑运算符
|-----------------|-------|-------|-------|
| 使用场景 | 与(并且) | 或(或者) | 非(取反) |
| test / \[\] | -a | -o | ! |
| \[] / (()) | & | &|| | ! |
4. 正则匹配
[[ 字符串 =~ ^[0-9]+$ ]] 可判断是否为纯数字、字母等格式
5. 实战案例
-
统计系统登录用户数
-
判断文件行数阈值
-
检测 SSH 服务是否运行
-
Ping 探测主机存活
-
键盘输入两数自动计算
五、流程控制
1. if 条件判断
-
单分支:满足条件执行
-
双分支:满足执行 A,否则执行 B
-
多分支:
if...elif...elif...else...fi
经典场景:root 权限校验、求最大值、内存告警、闰年判断、成绩评级
2. case 多分支匹配
适合固定值、区间匹配,替代多 elif,语法简洁
bash
case 变量 in
值1) 命令 ;;
值2) 命令 ;;
*) 默认命令 ;;
esac
常用于:菜单选择、星期判断、参数匹配
3. 四大循环
for 循环
-
列表循环:
for i in {1..10} -
命令结果循环:
for i in $(ls) -
C 语言风格:
for((i=1;i<=10;i++))
while 循环
条件为真持续执行,支持死循环 while true / while : 常用于:逐行读取文件、交互式猜数字
until 循环
条件不成立执行,成立终止,与 while 逻辑相反
select 循环
快速生成交互式数字菜单,可自定义 PS3 提示符
4. 循环控制关键字
-
break n:跳出当前 / 多层循环 -
continue n:跳过本次 / 多层本次循环 -
exit n:直接退出整个脚本
六、Shell 函数
1. 函数优势
代码复用、模块化、结构清晰、易维护、可移植
2. 函数定义语法
bash
# 写法1
function 函数名 {
命令
}
# 写法2
函数名() {
命令
}
3. 函数调用与传参
-
同文件直接调用:
函数名 参数1 参数2 -
跨文件调用:
source 函数库.sh加载后调用
4. 返回值与作用域
- 返回值
-
return只能返回 0-255 数字 -
echo可返回字符串、运算结果
- 变量作用域
-
无 local 默认全局变量
-
函数内
local 变量仅内部生效
5. 递归函数
函数调用自身,常用于:阶乘计算、递归遍历目录(模拟 tree)
七、Shell 数组
1. 数组分类
-
普通索引数组:下标为数字
-
关联数组:下标为字符串,需声明
declare -A arr
2. 数组定义方式
bash
# 直接赋值
arr=(a b c d)
# 下标单独赋值
arr[0]=1;arr[1]=2
# 命令结果赋值
arr=$(ls /etc)
3. 数组常用操作
bash
${arr[*]} # 获取所有元素
${!arr[*]} # 获取所有下标
${#arr[*]} # 获取数组长度
unset arr[n] # 删除指定元素
unset arr # 删除整个数组
4. 数组遍历
-
下标循环遍历
-
直接元素遍历