简介
Shell 脚本是一种解释型语言(区别于 C 语言等编译型语言),本质上是 Shell 命令的有序集合。
基本步骤
- 创建脚本文件
1
2
3
|
vi filename.sh
# 输入命令,例如
date
|
- 赋予执行权限
1
2
3
|
chmod 740 filename.sh
# 或者
chmod u+x filename.sh
|
- 执行脚本
Shell 变量
注意:等号两边不能加空格;变量名通常使用全大写。
用户自定义变量
支持创建变量存储数据,但不支持数据类型,任何赋给变量的值都是字符串。
1
2
|
COUNT=1
echo ${COUNT}
|
只读变量与删除
1
2
3
4
5
6
|
# 设置只读变量
myUrl="https://www.google.com"
readonly myUrl
# 删除变量
unset COUNT
|
字符串
1
2
3
4
5
|
# 获取字符串长度
echo ${#myUrl}
# 截取字符串(下标从 0 开始)
echo ${myUrl:1:4}
|
数组
Shell 只支持一维数组,元素类型可以不一致,可使用非连续下标。
1
2
3
|
array_name=(value0 value1 value2 value3)
echo ${array_name[0]} # 获取第一个元素
echo ${array_name[@]} # 获取所有元素
|
关联数组
1
2
3
4
5
|
#!/bin/bash
declare -A site # 定义关联数组(键值形式)
site["google"]="www.google.com"
site["runoob"]="www.runoob.com"
site["taobao"]="www.taobao.com"
|
位置变量
| 变量 |
说明 |
$# |
参数个数 |
$@ |
所有参数(参数分开) |
$* |
所有参数(作为整体) |
$? |
前一个命令的执行结果 |
$$ |
当前进程的 ID |
预定义变量
按位置传递参数:${0}、${1}、…
创建 test.sh:
1
2
3
4
5
6
|
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
|
执行:
1
2
3
4
5
6
7
|
$ chmod +x test.sh
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
|
环境变量
1
2
3
4
|
PATH=...
HOME=...
IFS=...
TERM=...
|
Shell 语句
Shell 有三大语句类型:说明性语句、功能性语句、结构性语句。
说明性语句
用于注释,不被执行。
1
2
3
4
5
|
# 单行注释
:<<EOF
多行注释内容...
EOF
|
功能性语句
读取输入
从标准输入读取一行赋值给变量;若标准输入无数据,则等待数据到来或程序终止。支持类似 Python 的解包形式:read var1 var2 var3。
算术运算
1
|
expr \( 10 + 10 \) \* 2
|
结果为 40。注意:需用反斜杠转义,运算符之间要有空格,表达式用反引号包围。
测试语句
test 命令用于检查条件是否成立,支持数值、字符和文件三种测试。
注意:返回 0 表示条件成立(true),返回非 0 表示条件不成立(false)。
1
2
3
|
test "$answer" = "yes" # 检查变量是否为字符串 yes
test $num -eq 18 # 检查变量是否等于 18
test -d tmp # 检查 tmp 是否为目录
|
数值测试
| 运算符 |
说明 |
-eq |
等于(equal) |
-ne |
不等于(not equal) |
-gt |
大于(greater than) |
-ge |
大于等于(greater or equal) |
-lt |
小于(less than) |
-le |
小于等于(less or equal) |
字符测试
| 运算符 |
说明 |
= |
相等(仅一个等号) |
!= |
不相等 |
-z 字符串 |
字符串长度为 0 |
-n 字符串 |
字符串长度不为 0 |
文件测试
1
2
3
|
-e 文件名 # 文件存在
-r 文件名 # 文件存在且可读
# ... 还有更多文件测试选项
|
布尔运算符
1
2
3
4
5
6
7
8
9
10
|
! # 非
-a # 与(and)
-o # 或(or)
# 示例
[ ! False ] # 非
[ $a -lt 20 -a $b -gt 100 ] # 与,等同于 [[ $a -lt 20 && $b -gt 100 ]]
[ $a -lt 20 -o $b -gt 100 ] # 或,等同于 [[ $a -lt 20 || $b -gt 100 ]]
# 优先级:! > -a > -o
|
输出命令
1
2
|
echo "..." > myfile # 输出重定向到文件
somecommand > /dev/null # 将输出丢弃到空设备
|
printf 与 echo 类似,但更适合格式化输出:
1
2
|
printf "%s\n" "Hello, World!"
# %s 是字符串格式符,\n 表示换行
|
结构性语句
分支语句
if 条件语句
常与 test 命令结合使用:
1
2
3
4
5
6
7
|
#!/bin/bash
if [ $# -ne 1 ] # 参数个数不等于 1 时执行 then
# 等同于 if (( $# -ne 1 ))
then
echo "usage : $0 filename"
exit
fi
|
配合 else、elif:
1
2
3
4
5
6
7
8
9
|
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
|
case 多路分支
类似 switch-case:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#!/bin/bash
echo -n "please choose (yes|no)?"
read R
case $R in # 注意 in
yes | Yes | y | Y | YES)
echo "yes"
;; # 类似 break
no | No | n | N | NO)
echo "no"
;;
*)
echo "wrong"
esac
|
循环语句
for 循环
1
2
3
4
5
6
|
#!/bin/bash
for I in `seq 1 2 10`
do
echo "$I"
done
# 输出 1 到 10,步长为 2
|
while 循环(条件为假时停止)
示例:输入 5 个数,判断等级:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#!/bin/bash
I=0
while [ $I -lt 5 ]
do
I=`expr $I + 1`
echo -n "input score:"
read S
case `expr $S / 10` in
9 | 10)
echo "A"
;;
6 | 7 | 8)
echo "B"
;;
*)
echo "C"
;;
esac
done
|
until 循环(条件为真时停止)
循环控制
1
2
|
break n # 跳出 n 层循环
continue n # 跳转到最近 n 层循环的下一轮
|
示例:遇到偶数跳出循环:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/bin/bash
if [ $# -ne 5 ]
then
echo "argument 5"
exit
fi
for I
do
if [ `expr $I % 2` -eq 1 ]
then
echo "$I"
else
break
fi
done
|
Shell 函数
定义格式
函数必须放在脚本开始部分定义:
1
2
3
4
5
|
[function] 函数名 [()]
{
action;
[return int;]
}
|
函数调用后会返回退出状态码,可通过 $? 获取:
1
2
|
funWithReturn
echo "执行上述函数的输出为 $?"
|
传递函数返回值
1
|
value_name=`function_name [arg1 arg2 ...]`
|
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
grep_user()
{
R=`grep "$1" /etc/passwd | wc -l`
echo $R
}
echo -n "input username:"
read USER
RET=`grep_user $USER`
echo "----return $RET----"
if [ $USER -eq 1 ]
then
echo "$USER exist"
else
echo "$USER not exist"
fi
|
获取函数返回状态
1
2
|
function_name [arg1 arg2 ...]
echo $?
|
变量作用域
- 全局作用域:脚本任何地方都可访问
- 局部作用域:仅在声明变量的作用域内访问
1
|
local variable_name=value
|
其他
Shell 脚本可以包含其他脚本,被包含的文件不需要可执行权限,只需在调用脚本中使用:
拓展与后续学习建议
- 正则表达式:学习基础正则和扩展正则,用于模式匹配和文本处理
- sed 流编辑器:实现自动化文本替换、删除、插入等操作
- awk 文本处理:强大的文本分析工具,适合处理结构化数据
- 函数封装技巧:学习函数的参数校验、错误处理和返回值设计
- 脚本调试方法:学习
bash -x 脚本名 调试模式,掌握 set -x、set -e 等调试选项
- 实际项目练习:尝试编写服务监控脚本、自动备份脚本等实用工具