shell脚本(略)
文章目录
- Shell编程从入门到实战:一篇搞定脚本开发核心技能
- 一、Shell基础:认识脚本的“灵魂”
- 1.1 什么是Shell?
- 1.2 常用Shell解释器
- 二、快速入门:编写第一个Shell脚本
- 2.1 脚本编写三步曲
- 步骤1:创建脚本文件
- 步骤2:编写脚本内容
- 步骤3:赋予执行权限并运行
- 2.2 脚本执行常见问题
- 三、核心语法:变量与字符串
- 3.1 变量定义与使用
- 变量特殊操作
- 3.2 字符串操作
- 字符串常用操作
- 四、参数传递:脚本接收外部输入
- 4.1 基础参数示例
- 4.2 特殊参数说明
- `$*`与`$@`的区别
- 五、流程控制:条件与循环
- 5.1 if条件判断
- 格式1:单支(满足条件执行)
- 格式2:双支(二选一执行)
- 格式3:多支(多选一执行)
- 常用条件表达式
- 5.2 for循环
- 格式1:数值循环(适合固定次数)
- 格式2:列表循环(适合遍历集合)
- 5.3 while循环
- 格式1:条件循环
- 格式2:无限循环(死循环)
- 5.4 case分支
- 六、函数与数组:模块化与数据存储
- 6.1 Shell函数
- 函数定义格式
- 函数调用与参数
- 6.2 数组操作
- 数组定义
- 数组常用操作
- 七、实战案例:猜数字游戏
- 八、总结与拓展
Shell编程从入门到实战:一篇搞定脚本开发核心技能
在Linux系统运维与开发中,Shell脚本是提高效率的“利器”——它能将复杂的命令序列封装成可复用的程序,实现自动化操作。本文基于Shell编程核心知识,从基础概念到实战案例,带你系统掌握Shell脚本开发,适合零基础入门与进阶学习。
一、Shell基础:认识脚本的“灵魂”
1.1 什么是Shell?
Shell是用C语言编写的命令解释器,它作为用户与Linux内核之间的“桥梁”,支持两种核心能力:
- 作为命令语言:直接在终端执行
ls
、cd
等命令,与系统交互; - 作为程序设计语言:通过编写脚本(
.sh
文件),实现逻辑控制、循环、函数等复杂功能。
类比理解:Shell类似Windows的cmd.exe
,但功能更强大,且是大多数Linux系统的默认交互工具。
1.2 常用Shell解释器
Linux支持多种Shell解释器,可通过cat /etc/shells
查看系统已安装的Shell,其中:
/bin/bash
:最常用的Shell,易用且免费,是CentOS、Ubuntu等系统的默认解释器;/bin/sh
:POSIX标准的Shell,是bash
的简化版;/sbin/nologin
:禁止用户登录的Shell(用于系统账号)。
后续所有案例均基于bash
编写,脚本开头需通过#!/bin/bash
指定解释器(“#!”是约定标记,告诉系统用哪个程序执行脚本)。
二、快速入门:编写第一个Shell脚本
2.1 脚本编写三步曲
以“打印Hello World”为例,完整流程如下:
步骤1:创建脚本文件
用vi
或vim
编辑器新建文件(扩展名.sh
仅为标识,不影响执行):
# 1. 创建存放脚本的目录(可选,建议规范管理)
mkdir shelldemo && cd shelldemo# 2. 新建脚本文件
vim hello.sh
步骤2:编写脚本内容
在hello.sh
中写入以下代码:
#!/bin/bash # 指定解释器为bash
echo "Hello World!" # 向终端输出文本
步骤3:赋予执行权限并运行
Shell脚本默认无执行权限,需通过chmod
命令授权,再执行:
# 赋予当前用户执行权限
chmod u+x ./hello.sh# 执行脚本(三种方式)
./hello.sh # 方式1:当前目录执行(推荐,需权限)
/root/shelldemo/hello.sh # 方式2:全路径执行(需权限)
sh hello.sh # 方式3:直接调用解释器(无需权限)
执行结果:终端输出Hello World!
,表示第一个脚本运行成功。
2.2 脚本执行常见问题
- 直接输入
hello.sh
报错?
Linux会从PATH
环境变量指定的目录中找命令,当前目录(.
)默认不在PATH
中,需用./hello.sh
明确路径。 - “权限不够”报错?
未执行chmod +x
授权,或用sh hello.sh
绕开权限检查。
三、核心语法:变量与字符串
3.1 变量定义与使用
Shell变量无需声明类型,直接赋值即可,核心规则:
- 格式:
变量名=值
(等号两边无空格,空格会被解析为命令分隔符); - 命名规则:首字符为字母,可含字母、数字、下划线,不能用bash关键字(如
if
、for
); - 使用方式:
$变量名
或${变量名}
(花括号用于明确变量边界,推荐加)。
示例:
#!/bin/bash
# 定义变量
your_name="bigdata.com"
age=20# 使用变量
echo $your_name # 输出:bigdata.com
echo ${age} # 输出:20
echo "My age is ${age}." # 边界明确,避免歧义
变量特殊操作
- 重新赋值:直接覆盖原有值,如
your_name="hadoop"
; - 只读变量:用
readonly
标记,赋值后不可修改,如readonly age=20
; - 删除变量:用
unset
删除普通变量(只读变量不可删),如unset your_name
。
3.2 字符串操作
字符串是Shell中最常用的数据类型,支持单引号、双引号、无引号三种形式,差异如下:
引号类型 | 特点 | 示例 | 输出结果 |
---|---|---|---|
单引号 | 原样输出,不解析变量和转义符 | str='I love $your_name' | I love $your_name |
双引号 | 解析变量和转义符(如\n ) | str="I love $your_name" | I love bigdata.com |
无引号 | 解析变量,但不保留空格 | str=I love $your_name | 报错(空格被解析为参数分隔) |
字符串常用操作
- 获取长度:
${#字符串}
,如${#your_name}
(计算"bigdata.com"
的长度为11); - 提取子串:
${字符串:起始索引:长度}
(索引从0开始),如${your_name:3:4}
(从第4个字符开始,取4个字符,结果为data
); - 查找子串:用
expr index "字符串" 子串
(位置从1开始),如expr index "I am good at hadoop" am
(输出3,表示“am”从第3个字符开始)。
四、参数传递:脚本接收外部输入
执行脚本时,可通过“脚本名+参数”的方式传递数据,脚本内通过$n
获取(n
为数字,$1
是第一个参数,$0
是脚本名)。
4.1 基础参数示例
编写demo1.sh
脚本,接收并打印参数:
#!/bin/bash
echo "脚本名:$0" # 输出脚本文件名
echo "第一个参数:$1" # 输出第一个参数
echo "第二个参数:$2" # 输出第二个参数
echo "参数总数:$#" # 输出参数总数
echo "所有参数(字符串):$*" # 所有参数合并为一个字符串
执行脚本并传递参数:
./demo1.sh 100 "hello"
输出结果:
脚本名:./demo1.sh
第一个参数:100
第二个参数:hello
参数总数:2
所有参数(字符串):100 hello
4.2 特殊参数说明
除了$0
、$1
、$#
,还有几个常用特殊参数:
参数 | 含义 | 示例(接上述执行命令) |
---|---|---|
$* | 所有参数合并为一个字符串 | "100 hello" |
$@ | 所有参数分开为独立字符串 | "100" "hello" |
$$ | 脚本运行的进程ID(PID) | 如12345 |
$? | 上一条命令的退出状态(0=成功,非0=失败) | 0(表示./demo1.sh 执行成功) |
$*
与$@
的区别
- 不加引号时:两者均以
$1 $2 ... $n
形式输出,无差异; - 加引号时:
"$*"
合并为一个字符串,"$@"
保留每个参数独立性(遍历参数时推荐用"$@"
)。
五、流程控制:条件与循环
5.1 if条件判断
Shell的if
语句用于“分支选择”,支持单支、双支、多支三种格式,核心是条件表达式(需用[ ]
包裹,括号内前后有空格)。
格式1:单支(满足条件执行)
#!/bin/bash
num=10
# 判断num是否为偶数
if [ $((num%2)) -eq 0 ]; thenecho "${num}是偶数"
fi
格式2:双支(二选一执行)
#!/bin/bash
num1=10
num2=20
if [ $num1 -gt $num2 ]; thenecho "${num1} > ${num2}"
elseecho "${num1} < ${num2}"
fi
格式3:多支(多选一执行)
#!/bin/bash
score=$1 # 从外部接收分数参数
if [ $score -ge 90 ]; thenecho "优秀"
elif [ $score -ge 80 ]; thenecho "良好"
elif [ $score -ge 60 ]; thenecho "及格"
elseecho "不及格"
fi
执行./score.sh 85
,输出良好
。
常用条件表达式
- 数字比较:
-eq
(等于)、-ne
(不等于)、-gt
(大于)、-lt
(小于)、-ge
(大于等于)、-le
(小于等于); - 字符串比较:
=
(等于)、!=
(不等于)、-z
(空字符串)、-n
(非空字符串); - 文件判断:
-f
(普通文件)、-d
(目录)、-e
(文件存在)、-x
(可执行)。
5.2 for循环
for循环用于“重复执行一段代码”,Shell支持两种常用格式:
格式1:数值循环(适合固定次数)
#!/bin/bash
# 计算1-10的累加和
sum=0
for ((i=1; i<=10; i++)); dosum=$((sum + i)) # 算术运算,$((表达式))
done
echo "1-10累加和:${sum}" # 输出:55
格式2:列表循环(适合遍历集合)
#!/bin/bash
# 遍历数组或列表
fruits=("apple" "banana" "cherry")
for fruit in ${fruits[@]}; do # @表示所有元素echo "水果:${fruit}"
done# 遍历目录下所有文件(用*通配符)
for file in $(ls /root/shelldemo); doecho "文件:${file}"
done
5.3 while循环
while循环通过“条件是否成立”控制循环,适合“不确定次数”的场景(如等待用户输入)。
格式1:条件循环
#!/bin/bash
# 输入yes/YES停止循环
y=""
while [ "$y" != "yes" -a "$y" != "YES" ]; do # -a表示逻辑与echo "请输入yes/YES停止循环:"read y # 接收键盘输入
done
echo "循环停止!"
格式2:无限循环(死循环)
用while true
实现,需在循环内加退出条件(如exit
):
#!/bin/bash
while true; doecho "请输入字符串:"read yif [ "$y" == "yes" ]; thenexit 0 # 退出脚本,终止循环fi
done
5.4 case分支
case用于“多值匹配”,类似其他语言的switch-case
,适合固定值判断(如参数匹配)。
示例:根据输入参数执行不同操作
#!/bin/bash
case $1 in"hello")echo "Hello World!";; # 结束当前分支(类似break)"test")echo "Testing...";;"")echo "请输入参数(如./casedemo.sh hello)";;*) # 默认分支,匹配所有未命中的值echo "默认操作";;
esac # case的反向拼写,标记分支结束
执行./casedemo.sh test
,输出Testing...
;执行./casedemo.sh other
,输出默认操作
。
六、函数与数组:模块化与数据存储
6.1 Shell函数
函数用于封装重复逻辑,实现代码复用,Shell函数需“先定义,后调用”。
函数定义格式
# 格式1:带function关键字
function 函数名() {函数体代码[return 返回值] # 可选,返回值为0-255的整数
}# 格式2:简化版(推荐)
函数名() {函数体代码
}
函数调用与参数
- 调用:直接写函数名,如
print_hello
; - 参数传递:调用时跟在函数名后(如
sum 10 20
),函数内用$1
、$2
获取(同脚本参数); - 返回值:用
return
返回整数,或用echo
输出结果(推荐,支持任意类型)。
示例1:无参无返回值函数
#!/bin/bash
# 定义函数
print_hello() {echo "Hello"echo "你好"
}# 调用函数
print_hello
示例2:带参带返回值函数(计算两数之和)
#!/bin/bash
# 定义求和函数
sum() {result=$(( $1 + $2 ))echo $result # 用echo输出结果(推荐)
}# 调用函数并接收结果
num1=10
num2=20
total=$(sum $num1 $num2) # $(命令)捕获命令输出
echo "两数之和:${total}" # 输出:30
6.2 数组操作
Shell仅支持一维数组,用于存储多个值,索引从0开始。
数组定义
# 方式1:直接赋值(元素用空格分隔)
fruits=("apple" "banana" "cherry")# 方式2:索引赋值(支持稀疏赋值)
fruits[0]="apple"
fruits[2]="cherry" # 索引1可空
数组常用操作
- 获取单个元素:
${数组名[索引]}
,如${fruits[0]}
(输出apple
); - 获取所有元素:
${数组名[*]}
或${数组名[@]}
(同参数传递的$*
与$@
); - 获取长度:
${#数组名[*]}
或${#数组名[@]}
,如${#fruits[@]}
(输出3); - 遍历数组:用for循环遍历所有元素,示例:
#!/bin/bash
fruits=("apple" "banana" "cherry")
# 遍历方式1:列表循环
for fruit in ${fruits[@]}; doecho $fruit
done# 遍历方式2:索引循环
len=${#fruits[@]}
for ((i=0; i<len; i++)); doecho ${fruits[$i]}
done
七、实战案例:猜数字游戏
基于前面的语法知识,编写一个互动性脚本——猜数字游戏,规则:
- 程序随机生成1-100的数字;
- 用户输入猜测值,程序提示“大了”“小了”或“猜对了”;
- 直到猜对,提示游戏结束。
完整代码(guess_number.sh
):
#!/bin/bash
# 生成1-100的随机数(RANDOM是系统变量,0-32767)
num=$[RANDOM%100+1]# 无限循环,直到猜对
while true; do# 提示用户输入(-p指定提示语)read -p "计算机生成了1-100的随机数,你猜:" cai# 判断猜测结果if [ $cai -eq $num ]; thenecho "恭喜,猜对了!"exit 0 # 猜对,退出脚本elif [ $cai -gt $num ]; thenecho "不巧,猜大了~"elseecho "不巧,猜小了~"fi
done
执行./guess_number.sh
,即可开始游戏,例如:
计算机生成了1-100的随机数,你猜:50
不巧,猜大了~
计算机生成了1-100的随机数,你猜:25
不巧,猜小了~
计算机生成了1-100的随机数,你猜:37
恭喜,猜对了!
八、总结与拓展
本文覆盖了Shell编程的核心知识点:从基础脚本编写,到变量、流程控制、函数、数组,最后通过实战案例巩固应用。掌握这些内容后,可进一步学习:
- 文件包含:用
source 文件名
或.
加载其他脚本的变量/函数,实现代码复用; - 正则表达式:结合
grep
、sed
、awk
处理文本数据; - 自动化运维:编写脚本实现日志切割、服务启停、定时任务(结合
crontab
)。
Shell脚本的核心价值是“自动化”——把重复的手动操作写成脚本,让计算机替你干活。多练多写(如批量处理文件、自动化部署),才能真正掌握这门技能。