Shell脚本(2)
文章目录
- Shell变量及赋值:从基础到实战的全面指南
- 一、Shell变量的本质与核心类型
- 二、自定义变量:从定义到使用的完整流程
- 1. 基础定义:赋值语法与规则
- 正确与错误示例对比
- 2. 变量的引用:`$`与`${}`的用法
- 示例1:基础引用(无歧义场景)
- 示例2:`${}`的必要性(有歧义场景)
- 3. 变量的查看与删除
- 三、赋值的“花样操作”:引号、命令替换与交互
- 1. 引号的区别:双引号`"`、单引号`'`、反撇号`` ` ``
- 实战示例:三种引号的效果对比
- 2. 交互式赋值:`read`命令获取用户输入
- 实战示例1:基础交互(输入姓名)
- 实战示例2:隐藏输入(输入密码)
- 实战示例3:从文件读取内容赋值
- 四、变量的作用范围:局部与全局的切换
- 1. 局部变量的局限性
- 2. `export`:导出全局变量
- 实战示例:导出全局变量
- 查看与取消全局变量
- 五、特殊变量:只读变量与预定义变量
- 1. 只读变量:`readonly`,定义后不可修改
- 2. 预定义变量:Shell内置的“工具变量”
- 实战示例:预定义变量的用法
- 六、总结:Shell变量的核心要点
Shell变量及赋值:从基础到实战的全面指南
在Shell脚本编程中,变量是承载临时数据的核心载体,也是实现脚本灵活性和可维护性的基础。无论是简单的命令行操作,还是复杂的自动化脚本,掌握变量的定义、赋值与使用逻辑,都是提升效率的关键。本文将从变量的本质出发,详细讲解Shell中变量的类型、赋值方式、作用范围及实战技巧,帮你彻底搞懂Shell变量的“前世今生”。
一、Shell变量的本质与核心类型
变量的核心作用是“临时存储可变化的数据”,避免重复编写固定内容——比如脚本中多次用到的路径、版本号、用户输入等,用变量替代后,修改时只需改一处即可。
Shell中的变量无需提前声明类型(弱类型语言),直接赋值即可使用。根据作用场景,常见变量可分为5类:
变量类型 | 作用说明 | 典型示例 |
---|---|---|
自定义变量 | 用户手动定义,仅在当前Shell环境生效(局部变量) | name="Linux" 、version=2.0 |
环境变量 | 全局生效,可在所有子Shell中使用,常用于配置系统环境(如路径、语言) | PATH 、HOME 、LANG |
只读变量 | 定义后不可修改或删除,避免误操作导致数据丢失 | readonly PI=3.14 |
位置变量 | 接收脚本执行时传入的参数,按顺序对应($1代表第1个参数,$2代表第2个) | ./script.sh arg1 arg2 中,$1=arg1 |
预定义变量 | Shell内置的“开箱即用”变量,用于获取脚本执行状态、参数数量等 | $? (上条命令状态码)、$# (参数总数) |
二、自定义变量:从定义到使用的完整流程
自定义变量是日常使用最频繁的类型,核心语法简单,但细节(如符号、空格)直接影响正确性。
1. 基础定义:赋值语法与规则
自定义变量的赋值格式严格遵循 变量名=变量值
,且有3个关键规则:
- 等号
=
前后不能有空格(否则Shell会把变量名当命令执行); - 变量名必须以字母或下划线开头,不能包含特殊字符(如
+
、-
、*
、$
等); - 变量值若包含空格或特殊符号,需用双引号
"
或单引号'
包裹(下文详解引号区别)。
正确与错误示例对比
# 正确:等号无空格,变量名合规
product="Shell教程"
version=1.0
install_path="/usr/local/shell"# 错误1:等号有空格(Shell会把“name”当命令,“Linux”当参数)
name = "Linux" # 报错:bash: name: 未找到命令...# 错误2:变量名以数字开头(不符合命名规则)
123version=2.0 # 报错:bash: 123version=2.0: 语法错误: 无效的算术运算符
2. 变量的引用:$
与${}
的用法
引用变量时,需在变量名前加$
符号;若变量名后紧跟其他字符(如字母、数字),需用${}
包裹变量名,避免Shell误判变量范围。
示例1:基础引用(无歧义场景)
product="Python"
version=3.11
# 直接用$引用变量,拼接字符串
echo "当前版本:$product $version" # 输出:当前版本:Python 3.11
示例2:${}
的必要性(有歧义场景)
若想输出“Python3.11”(变量后直接跟数字),不写${}
会报错:
# 错误:Shell会把$product3.11当作一个变量(未定义,输出空)
echo "$product3.11" # 正确:用${}明确变量范围,仅引用$product
echo "${product}3.11" # 输出:Python3.11
3. 变量的查看与删除
- 查看变量值:用
echo $变量名
或echo ${变量名}
; - 删除变量:用
unset 变量名
(删除后变量值为空,不可恢复)。
name="Tom"
echo $name # 输出:Tom# 删除变量
unset name
echo $name # 输出:(空值,变量已被删除)
三、赋值的“花样操作”:引号、命令替换与交互
除了“变量名=固定值”的基础赋值,Shell还支持更灵活的赋值方式,应对空格、特殊字符、命令结果、用户输入等场景。
1. 引号的区别:双引号"
、单引号'
、反撇号`
引号的核心作用是“界定字符串范围”,但不同引号对变量和特殊字符的处理逻辑完全不同,这是Shell变量的高频考点。
引号类型 | 对变量的处理 | 对特殊字符($、\、`)的处理 | 适用场景 |
---|---|---|---|
双引号" | 识别变量(会替换为变量值) | 识别部分转义(如\n 、\t ) | 变量值含空格,需保留变量引用 |
单引号' | 不识别变量(原样输出$变量名 ) | 所有字符均为普通字符(无转义) | 变量值含特殊符号(如$、`),需原样输出 |
反撇号` | -(不用于界定字符串) | 执行引号内的命令,返回结果 | 赋值为“命令执行后的输出” |
实战示例:三种引号的效果对比
# 先定义一个基础变量
test_var="Linux"# 1. 双引号:识别变量,保留空格
echo "变量值:$test_var,当前目录:$(pwd)" # 输出:变量值:Linux,当前目录:/root# 2. 单引号:不识别变量,特殊字符原样输出
echo '变量值:$test_var,当前目录:$(pwd)' # 输出:变量值:$test_var,当前目录:$(pwd)# 3. 反撇号:执行命令,赋值为结果(与$()等价)
current_time=`date +%H:%M:%S` # 执行date命令,将时间赋值给变量
echo "当前时间:$current_time" # 输出:当前时间:15:30:45
注意:反撇号
`
不支持嵌套命令(如`ls `which python`
会报错),推荐用$()
替代,嵌套更灵活:
rpm -qc $(rpm -qf $(which useradd))
(先找useradd路径,再查对应rpm包的配置文件)
2. 交互式赋值:read
命令获取用户输入
当脚本需要“让用户手动输入内容”时(如输入密码、姓名),用read
命令实现交互。read
支持多种选项,优化交互体验:
选项 | 作用说明 |
---|---|
-p "提示信息" | 显示提示文本,告知用户需要输入什么(无需额外用echo输出提示) |
-s | 输入内容不回显(隐藏输入,常用于输入密码) |
-n 字符数 | 限制输入的字符长度(输入达到指定长度后自动结束,无需按回车) |
-t 秒数 | 超时时间(超过指定秒数未输入,自动退出,避免脚本卡住) |
实战示例1:基础交互(输入姓名)
# 用-p显示提示,输入内容赋值给name变量
read -p "请输入你的姓名:" name
echo "你好,$name!" # 输出:你好,张三!(假设输入张三)
实战示例2:隐藏输入(输入密码)
# -s隐藏输入,-p提示,输入后赋值给pass变量
read -s -p "请输入密码:" pass
echo -e "\n密码已接收(已隐藏)" # -e识别\n换行,避免输出紧跟在输入后
实战示例3:从文件读取内容赋值
read
还支持从文件读取内容(而非键盘输入),用<
指定文件路径:
# 先创建一个文件,写入IP地址
echo "192.168.1.100" > ip.txt# 从ip.txt读取内容,赋值给ip变量
read -p "读取IP:" ip < ip.txt
echo "获取的IP:$ip" # 输出:获取的IP:192.168.1.100
四、变量的作用范围:局部与全局的切换
默认情况下,自定义变量是“局部变量”——仅在当前Shell环境生效,进入子Shell(如执行bash
命令打开新Shell)后,局部变量会失效。若需变量在所有子Shell中可用,需用export
命令导出为“全局变量”。
1. 局部变量的局限性
# 在当前Shell定义局部变量
name="张三"
echo "当前Shell:$name" # 输出:当前Shell:张三# 进入子Shell(新的Shell环境)
bash
echo "子Shell:$name" # 输出:子Shell:(空值,局部变量失效)# 退出子Shell,回到原Shell
exit
echo "回到原Shell:$name" # 输出:回到原Shell:张三(原变量仍在)
2. export
:导出全局变量
export
的作用是“将局部变量提升为全局变量”,支持两种用法:
- 先定义变量,再导出:
变量名=值; export 变量名
; - 定义时直接导出:
export 变量名=值
。
实战示例:导出全局变量
# 方式1:先定义,再导出
version=2.0
export version # 导出为全局变量
# 方式2:定义时直接导出
export author="李四"# 进入子Shell,验证全局变量
bash
echo "子Shell:version=$version, author=$author" # 输出:子Shell:version=2.0, author=李四# 退出子Shell
exit
查看与取消全局变量
- 查看全局变量:用
env
命令(列出所有环境变量),或echo $变量名
; - 取消全局变量:用
export -n 变量名
(将全局变量变回局部变量,子Shell中不再生效)。
# 取消version的全局属性
export -n version# 进入子Shell,验证
bash
echo "子Shell version:$version" # 输出:子Shell version:(空值,已变回局部)
exit
五、特殊变量:只读变量与预定义变量
除了自定义变量,Shell还提供两种特殊变量:只读变量(防修改)和预定义变量(内置工具),解决特定场景需求。
1. 只读变量:readonly
,定义后不可修改
用readonly
定义的变量,无法用unset
删除,也不能重新赋值,适合存储固定不变的常量(如π值、配置路径)。
# 定义只读变量
readonly PI=3.14159
echo "π值:$PI" # 输出:π值:3.14159# 尝试修改(报错)
PI=3.14 # 报错:bash: PI: 只读变量# 尝试删除(报错)
unset PI # 报错:bash: unset: PI: 无法取消设定: 只读 variable
2. 预定义变量:Shell内置的“工具变量”
预定义变量是Shell自带的,无需手动定义,直接引用即可,常用于脚本调试、参数处理、状态判断。
预定义变量 | 作用说明 |
---|---|
$? | 上一条命令的执行状态码:0=成功,非0=失败(如1=语法错误,2=参数错误) |
$# | 脚本执行时传入的参数总数(如./script.sh a b c ,$#=3) |
$* | 所有参数的集合(将所有参数视为一个整体,用空格分隔) |
$@ | 所有参数的集合(将每个参数视为独立个体,适合循环遍历) |
$$ | 当前Shell或脚本的进程ID(PID) |
$! | 上一个后台运行命令的进程ID(PID) |
实战示例:预定义变量的用法
# 1. $?:判断上条命令是否成功
ls /tmp # 执行一个正确的命令
echo "ls命令状态码:$?" # 输出:ls命令状态码:0(成功)ls /nonexistent # 执行一个错误的命令(目录不存在)
echo "ls错误状态码:$?" # 输出:ls错误状态码:2(失败)# 2. $#、$*、$@:处理脚本参数(假设脚本名为test.sh)
#!/bin/bash
echo "参数总数:$#" # 输出参数个数
echo "所有参数(整体):$*" # 输出所有参数
echo "所有参数(独立):$@" # 输出所有参数# 执行脚本:./test.sh arg1 arg2 arg3
# 输出结果:
# 参数总数:3
# 所有参数(整体):arg1 arg2 arg3
# 所有参数(独立):arg1 arg2 arg3
六、总结:Shell变量的核心要点
- 赋值语法:
变量名=变量值
,等号无空格,特殊值用引号包裹; - 引号逻辑:双引号识别变量,单引号原样输出,反撇号/
$()
执行命令; - 作用范围:局部变量仅当前Shell有效,
export
导出为全局变量; - 特殊场景:
read
实现交互,readonly
定义常量,预定义变量简化脚本; - 避坑提醒:变量引用加
$
,歧义场景用${}
,$?
判断命令状态。
掌握这些内容后,无论是写简单的命令行脚本,还是复杂的自动化工具,都能灵活运用变量提升效率,避免重复劳动和语法错误。Shell变量看似基础,却是通往Shell编程进阶的“第一道门”——打好基础,后续的循环、条件、函数等内容都会更易理解。