一、shell脚本
(一)shell基本结构
文件扩展名:通常习惯用 .sh 作为扩展名,不是强制要求。关键在于文件开头的 shebang 行。
shebang 行:一般写成 #!/bin/bash ,这行的作用是指定执行脚本的shell 解释器路径。
(二)注释规范
单行注释:以 # 开头,# 后面的是注释内容;
多行注释:在 Bash 中可以用 <<EOF 和 EOF 包裹起来(类似C语言的/* */);
(三)shell脚本执行方式
1. 赋予执行权限后直接运行:chmod +x xxx.sh && ./xxx.sh
例如:chmod +x demo.sh && ./demo.sh == chmod +x demo.s、 ./demo.sh
2. shell解释器运行:bash xxx.sh 或者是 sh xxx.sh
3. 使用source 执行:source xxx.sh 或者是 . xxx.sh (.是source的简写)
二、变量定义与使用
(一)变量的定义
命名规则:变量名由字母、数字和下划线组成,且不能以数字开头。
赋值格式:(等号左右两边不允许有空格)
- 变量名=初始值
- 变量名=' 初始值'
- 变量名="初始值"
注意:当变量的初始值包含空格时,需用单引号或双引号括起来,否则会报错。
在shell中定义的变量没有数据类型,变量的值都视为字符串;如:num=12345678;
变量调用方式:使用 ${变量名} 形式来引用变量的值,可避免歧义。例如:str2="${str1}world",将str1后面加上world,整体赋值给str2。
(二)变量的类型
系统变量
由系统自动设置,提供有关系统和 shell 环境的信息,可在所有脚本中访问。
示例:$HOME(用户主目录)、$USER(当前用户名)等;可使用 echo $变量名 或 set 命令查看。
用户变量
由用户在脚本中创建并赋值,仅在当前 shell 脚本或会话中有效。
赋值与使用:变量名=值,引用时使用 ${变量名} ;删除用 unset 变量名;
环境变量
可在当前 shell 进程及其子进程中都能访问的变量。
声明方法:使用 export 变量名=值 (变量名=值 、export 变量名)。
局部变量
仅在当前 shell 进程或脚本中有效,未export 的用户变量默认为隐式局部变量;局部变量只在函数内部有效,函数执行完毕后,局部变量就会被销毁。
(三)特殊变量与位置参数
特殊变量
$0:表示当前脚本的名称;
$?:表示上一条命令的退出状态码,0 表示命令执行成功,非 0 表示命令执行失败;
位置参数
执行脚本时可传递参数,在脚本中通过特定变量获取;
$1 - $9:依次对应执行脚本时传递的第 1 - 9 个参数;10及以上:如 {10} 表示第 10 个参数,用于获取序号大于 9 的参数;
$*:包含执行脚本时传递的所有参数(不含脚本文件名),循环中会将所有参数当作一个整体处理。
$@:同样表示执行脚本时传递的所有参数(不含脚本文件名),循环中会逐个处理每个参数。
$#:表示执行脚本时传递的参数个数(不含脚本文件名)。
chmod +x demo.sh && ./demo.sh 10 20


(四)修饰变量的关键字
readonly 关键字
定义:用于修饰变量,使其成为只读属性,赋值后不可再修改。
语法:readonly 变量名=值,或先赋值再 readonly 变量名:变量名=值、readonly 变量名;
应用场景:定义程序中的常量,如配置文件路径、版本号;保护关键变量不被意外修改。
注意:只读变量不能使用 unset 删除;重新定义同名变量也无法覆盖只读属性。
unset 关键字
定义:用于取消变量的定义,删除后变量引用返回空值。
语法:unset 变量名
应用场景:释放不再使用的变量,节省内存;清除包含敏感信息的变量(如密码)。
注意:对 readonly 修饰的变量使用 unset 会报错;若变量未定义,使用 unset 不会报错(对同一个变量多次使用 unset 不会报错)。
local 关键字
定义:在函数内部使用,用于创建局部变量,仅在函数内有效。
语法:function 函数名() { local 变量名=值; }
应用场景:避免函数内变量污染全局作用域;保护函数内部的临时数据。
注意:函数外使用 local 会报错。
三、算术运算
(一)expr 命令(不常用)
expr 操作数1 运算符 操作数2:操作数与运算符间需空格,部分运算符(如*)需转义,例如:expr 5 \* 3
(二)双括号((...))
((变量= 表达式)):支持C 风格运算符(如++、+= 等),可直接修改变量值((a = 5 + 3))
(三)$((...))
$((表达式)):用于直接替换算术表达式结果,类似expr 但语法更现代,无需空格,支持常见算术运算符,如:echo $((5 + 3))
四、数组
在 shell 中,数组仅支持一维,无需预先定义大小,元素可为字符串、数字等任意类型,元素间用空格分隔,索引默认从 0 开始。
赋值:
- 直接赋值法:通过括号包裹元素列表赋值;数组名=(元素1 元素2 元素3 ...)
- 逐个赋值法:为指定索引的元素赋值;数组名[索引]=元素
访问单个元素:用 ${数组名[索引]} 获取指定索引的元素(索引可为数字或变量);
访问所有元素:
- ${数组名[@]}:将每个元素作为独立参数,适合循环遍历;
- ${数组名[*]}:将所有元素作为整体字符串(元素间用默认空格分隔);
- 获取数组长度:用 ${#数组名[@]} 或 ${#数组名[*]} 获取元素个数;
末尾添加:自动在最大索引 +1 处添加元素;数组名+=("新元素")
指定索引添加:为指定索引赋值(不存在则创建新元素)。数组名[新索引]="新元素"
修改元素:通过索引重新赋值;数组名[索引]="新值"
删除元素:用 unset 删除指定索引元素(数组变稀疏,索引不重排);unset 数组名[索引]
截取数组:获取指定范围元素;${数组名[@]:起始索引:长度}(长度可选,缺省则到末尾)
五、条件判断
(一)if ((表达式))
1. if
if ((表达式)); then
shell语句
fi
当 ((表达式)) 的结果为非零值(即条件为真)时,执行then后的语句;((表达式))是bash特有的算术表达式,支持+、-、*、/、>、<等运算符。
2. if-else
if ((表达式)); then
shell语句1
else
shell语句2
fi
当表达式为真时,执行语句1;否则执行shell语句2;
3. if-elif-else
if ((表达式1)); then
shell语句1
elif ((表达式2)); then
shell语句2
elif ((表达式3)); then
shell语句3
...
else
shell语句4
fi
按顺序检查每个表达式,一旦某个表达式为真,则执行对应的语句块,并跳过后续所有elif和else;如果所有表达式都为假,此时有else,则执行else后的语句;没有else,则直接退出程序。
(二)test命令
test 表达式或 [ 表达式 ](本质上是调用 test 命令)。
注意:使用方括号 [ ] 这种形式时,在表达式中,参数、运算符以及中括号前后都必须添加空格;方括号与表达式之间也必须保留空格;变量需要用双引号引起来,以防止变量为空或包含空格时出现问题。

test 命令的返回状态码为 0 表示条件成立,非 0 表示条件不成立。当 test 命令执行完毕后,退出码为 0 时,if 判定条件成立,执行 then;当退出码不为 0 时,if 判定条件失败,执行 else。
(三)if与test联合使用 if [ ]
1. 数值判断
用于比较两个整数的大小关系,返回状态码0 (真)或1 (假);脚本中需要比较数字大小的逻辑(如判断年龄、版本号等等);循环条件(如while [ $i -le 10 ]);判断条件(如if [ "$n" -eq 10 ])。

2. 字符串判断
test 配合 if 使用可以用于判断字符串的状态(是否为空、非空),比较字符串间是否相等、大小关系等;返回状态码 0 (真) 或 1 (假)。
-z:如果 string 的长度为0(即空字符串),则条件为真,如:-z "$str"→ 假(str 非空)。


-n :如果 string 的长度大于0(即非空字符串),则条件为真,如:-n "$str"→ 真(str 非空)。
=/== :如果两个字符串相等,则条件为真。= 和 == 等价,如:"$str" =/== "hello"→ 真
!= :如果两个字符串不相等,则条件为真,如:"$str" != "world"→ 真
'>' (需要转义):如果str1 按字典序大于 str2,则条件为真;如:"$str" '>' "abc"→ 真
'<' (需要转义):如果str1 按字典序小于 str2,则条件为真,如:"$str" '<' "world"→ 真
>、< 都需要转义,可以使用 '>' 或 \> 转义。
3. 逻辑判断
逻辑判断用于组合多个条件表达式,形成更复杂的判断。(假设 a=10, b=20)
-a:逻辑与,同时都满足,如:[ "$a" -gt 5 -a "$b" -lt 30 ] (a>5且b<30,为真)
-o:逻辑或,满足其一即可,如:[ "$a" -eq 0 -o "$b" -eq 20 ](真)
! :逻辑非,取反,如:[ ! -d "$dir" ] → 若目录不存在则为真
4. 文件判断
用于检查文件或目录的状态(是否存在、类型、权限等),返回状态码 0 (真) 或 1 (假);
注意:始终用双引号包裹变量:防止路径或变量值包含空格、通配符时被shell错误解析。

(四)if [[ ]]
if [[ 条件表达式1 ]]; then
shell语句1
elif [[ 条件表达式2 ]]; then
shell语句2
else
shell语句3
fi
无需转义特殊字符,语法更简洁:在 [[ ... ]] 中,传统 [ ... ] 需要转义的特殊符号(如 >、<、!等)可直接使用,无需添加反斜杠 \ 或引号包裹。
支持短路求值,提升执行效率:逻辑操作符 &&(逻辑与)和 ||(逻辑或)具备短路特性。
- 当 && 左侧条件为假时,右侧条件不再执行;
- 当 || 左侧条件为真时,右侧条件不再执行;
安全处理未定义变量:若变量未定义,[[ ... ]] 会将其视为空字符串,避免 [ ... ] 可能触发的语法错误。
(五)case...in(类switch)
case...in 是多路分支结构,用于根据不同的条件执行相应的代码块。类 switch - case 语句。
case 变量 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
*) #其他情况
默认命令序列
;;
esac
(六)select...in
select...in :用于创建交互式菜单的专用命令,主要用于引导用户通过键盘输入选择预设选项。它会自动为每个选项生成编号(从 1 开始),用户输入对应数字即可触发相应操作,适合需要频繁与用户交互的场景(如脚本配置、功能选择等)。
select 变量名 in 选项1 选项2 选项3...
do
命令序列
[break] # 可选,用于退出循环
done
六、循环结构
(一)for
适用于已知要遍历的元素集合(如数组、列表)或明确循环次数的场景,通过依次迭代集合元素或按指定数字范围来执行循环体。遍历目录下文件、对数组元素逐一操作、按指定次数执行任务等。
遍历列表:
for 变量 in 列表或数组元素; do
命令1
命令2
...
done
数字范围循环:
for ((初始值; 条件; 增量或减量)); do
命令1
命令2
...
done
(二)while
根据条件判断结果决定是否执行循环体,只要条件为真就持续循环(返回状态码 0),直到条件为假时结束,适用于条件动态变化或不确定循环次数的情况。
while 条件判断; do
命令1
命令2
...
done
(三)until
与while循环相反,until循环基于条件判断结果决定是否执行循环体,不过是条件为假时持续循环,一旦条件变为真就结束循环,适用于需要等待某个条件达成的场景;
until 条件判断; do
命令1
命令2
...
done

在需要等待特定条件从假变为真的场景中,逻辑表达更自然清晰,避免在while循环中使用双重否定条件(例如不必写while [ ! -f file.txt ],而是直接用until [ -f file.txt ])。
七、函数
(一)函数语法格式
标准格式:
function 函数名() {
命令1
命令2
...
[return 返回值] # 可选,返回值范围0-255
}
简化格式(省略function关键字):
函数名() {
命令1
命令2
...
}
(二)函数调用与参数
直接使用函数名即可调用,若函数需要参数,直接跟在函数名后面,参数之间用空格分隔。


参数传递:在 shell 中,函数通过位置参数接收传递给它的参数。
$1, $2, ..., $n:表示第 1 到第 n 个参数。
$0:表示脚本本身的名称,在函数内部使用时,它仍然表示脚本名,而不是函数名。
$#:表示参数的个数。 $@或$*:表示所有参数。
$@将参数视为独立的个体。 $*将所有参数视为一个整体。
通过return语句返回状态码:设置函数的退出状态码(范围 0-255),用于表示函数执行的成功(0)或失败(非 0)。状态码可通过 $? 变量获取,但仅能是整数;return语句会立即终止函数执行,类似exit但仅作用于函数。return 的值就是 $? 的值,范围 0~255。
(三)函数输出捕获
函数输出捕获是获取函数实际计算结果(如字符串、数值等)的手段;
return 语句(仅用于返回状态码):设置函数退出状态码,需结合$?获取;仅能返回整数(0-255);主要用于表示执行状态,而非数据结果。
使用 echo 输出 + 命令替换捕获:通过echo将结果输出到标准输出,再用 $(...) (常用)或反引号`捕获;支持任意类型数据(字符串、数字、多行内容)。


1581

被折叠的 条评论
为什么被折叠?



