一、变量基础概念
1.1 什么是变量?
变量是命名的内存空间,用于存储数据(如字符串、数字等)。通过变量名可以快速引用和操作这些数据,避免重复输入复杂内容。
1.2 变量的作用
•
简化操作:用有意义的名称代替重复的数据(如 PATH=/usr/bin:/usr/local/bin)。
•
灵活控制:通过修改变量值动态调整脚本行为(如根据用户输入切换路径)。
•
提高可读性:清晰的变量名让代码更易理解(如 USER_NAME=admin比直接写 admin更直观)。
二、变量类型
Shell中的变量按用途和特性分为以下几类:
类型
说明
示例
内置变量
Shell预定义的系统变量(只读或全局生效),如 PATH(命令搜索路径)、UID(用户ID)
echo $PATH查看命令搜索路径
用户自定义变量
用户手动定义的变量,用于存储脚本中需要的数据
name="Tom"
预定义变量
Shell内置的特殊变量(如 $0、$?),用于获取脚本执行相关信息
$0表示脚本名称,$?表示上一条命令的退出状态
位置变量
用于接收脚本运行时传递的参数(如 $1、$2...),对应第1、第2个参数
执行 ./script.sh arg1 arg2时,$1是 arg1,$2是 arg2
2.1 变量数据类型
•
字符串:文本数据(如 "Hello"、'World'),Shell默认所有变量均为字符串。
•
数值:
•
整型:整数(如 10、-5),Bash可直接处理。
•
浮点型(小数):Bash不支持(如 3.14需借助外部工具如 bc计算)。
三、变量命名规则
3.1 合法命名要求
•
字符限制:只能包含 数字、字母、下划线(如 user_name、AGE_20)。
•
禁止数字开头:不能以数字开头(如 1name❌,name1✅)。
•
避开保留字:不能使用Shell关键字(如 if、for、while)。
•
推荐命名风格:
•
见名思义:变量名体现用途(如 username比 a更清晰)。
•
统一规范:
•
全大写:环境变量或全局常量(如 PATH、MAX_SIZE)。
•
小写:局部变量和函数名(如 count、calculate_sum)。
四、变量的定义与使用
4.1 定义变量
格式:变量名="值"(等号两侧不能有空格!)
常见赋值方式:
name='Mike' # 直接字符串(单引号包裹,内容原样输出)
NAME="$USER" # 引用其他变量(双引号内变量会被解析)
hostname=`hostname` # 命令结果(反引号,旧写法)
hostname=$(hostname) # 命令结果(推荐,更清晰的 $( ) 写法)
FILE=/etc/* # 通配符(匹配 /etc 下所有文件)
⚠️ 注意:变量赋值仅在当前Shell进程中有效,关闭终端后自动失效(除非写入配置文件如 ~/.bashrc)。
4.2 引用变量
•
基本引用:$变量名(如 echo $name)或 ${变量名}(推荐,避免歧义)。
•
弱引用 vs 强引用:
•
弱引用 $var:变量会被替换为实际值(如 echo "Name: $name"→ 输出 Name: Mike)。
•
**强引用 'var′‘∗∗:变量保持原字符串(如‘echo′Name:name'→ 输出Name: $name`)。
4.3 特殊场景:变量名相邻时的处理
若变量名与其他字符相连(如 ${NAME}_AGE),必须用 ${ }明确边界,否则Shell会误解析:
NAME=mage
echo $NAME_AGE # 错误!Shell尝试找变量 NAME_AGE(不存在,默认为空)
echo ${NAME}_AGE # 正确!输出 "mage_AGE"
五、变量作用域
变量的生效范围(作用域)决定了它能在哪些Shell进程中使用:
类型
生效范围
示例场景
普通变量
当前Shell进程
在终端直接定义的变量(如 name="Tom"),子Shell(如新开的终端窗口)无法访问。
环境变量
当前Shell及其所有子进程
通过 export 变量名=value定义(如 export PATH=/new/path:$PATH),子进程可继承。
本地变量
当前Shell的某个代码片段(如函数内部)
函数内定义的变量(默认仅函数内可用,除非用 local声明为局部变量)。
📌 环境变量通常用于配置全局信息(如 PATH),普通变量多用于脚本内部临时存储。
六、常用变量操作命令
6.1 查看所有变量
•
set:显示所有变量(包括用户自定义、环境变量、函数等)。
•
env或 printenv:仅显示环境变量。
•
export:显示已导出的环境变量。
•
declare -x:同 export,显示环境变量。
6.2 删除变量
unset 变量名1 变量名2 # 删除指定变量(如 unset name age)
删除后,该变量不可再被引用(echo $变量名输出空)。
七、特殊变量详解
7.1 环境变量
•
作用:子进程(包括孙子进程)可继承父进程的环境变量,但子进程的修改不会影响父进程。
•
定义方法:
export 变量名=value # 推荐写法(先赋值再导出)
变量名=value; export 变量名 # 分步写法
declare -x 变量名=value # 使用 declare 命令
•
示例:让子脚本使用父脚本定义的变量
# father.sh
#!/bin/bash
NAME="father"
export NAME # 导出为环境变量
echo "Father: $NAME"
./son.sh # 调用子脚本
# son.sh
#!/bin/bash
echo "Son: $NAME" # 子脚本可访问父脚本导出的 NAME
NAME="son" # 子脚本修改自己的 NAME(不影响父脚本)
echo "Son修改后: $NAME"
7.2 只读变量
•
特点:定义后不可修改、不可删除,用于存储固定值(如配置常量)。
•
定义方法:
readonly 变量名=value
declare -r 变量名=value
•
示例:
readonly PI=3.14
PI=3.14159 # 报错:PI: 只读变量
unset PI # 报错:无法删除只读变量
7.3 位置变量
用于接收脚本运行时传递的参数(通过命令行传入):
变量
说明
示例(执行 ./script.sh A B C)
$0
脚本名称(含路径)
./script.sh或完整路径
$1
第1个参数
A
$2
第2个参数
B
...
...
...
$9
第9个参数
(超过9需用 ${10}语法)
$#
参数的总个数
3(对应 A/B/C)
$*
所有参数合并为单个字符串
A B C
$@
所有参数为独立字符串
ABC(双引号内差异明显)
$?
上一条命令的退出状态码
0(成功)或非0(失败)
$$
当前Shell进程的PID
脚本自身的进程ID
📌 注意:$*和 $@在双引号中表现不同:
•
"$*":所有参数合并为一个字符串(如 "A B C")。
•
"$@":每个参数作为独立字符串(如 "A" "B" "C"),推荐在循环中遍历参数时使用。
7.4 退出状态码变量 $?
•
作用:存储上一条命令或函数的执行结果(0表示成功,非0表示失败)。
•
常见状态码:
•
0:成功。
•
1:一般错误(如参数错误)。
•
127:命令未找到(如输入了错误的命令名)。
•
自定义退出:通过 exit n主动设置脚本退出状态(如 exit 0表示成功)。
八、变量操作进阶
8.1 命令替换
通过命令执行结果赋值给变量:
# 反引号(旧写法)
current_date=`date +%Y-%m-%d`
# 推荐写法($( ))
current_dir=$(pwd)
files_count=$(ls | wc -l)
8.2 数值计算(整型)
Bash默认不支持浮点数,但可通过 $(( ))或 let进行整数运算:
a=10
b=20
sum=$((a + b)) # sum=30
let "product=a*b" # product=200
8.3 展开命令行规则
Shell处理命令行时按以下顺序:
1.
拆分命令词 → 2. 展开别名 → 3. 处理 {}大括号 → 4. 处理 ~家目录 → 5. 命令替换 $( )或 ` `→ 6. 再次拆分词 → 7. 处理通配符 */?→ 8. 准备输入/输出重定向 >→ 9. 执行命令。
8.4 防止扩展(避免特殊字符被解析)
•
**反斜线 \`**:转义单个字符(如echo Your cost: $5.00→ 输出Your cost: $5.00`)。
•
引号:
•
单引号 ' ':禁止所有扩展(如 echo '$PATH'→ 输出 $PATH)。
•
双引号 " ":允许部分扩展(如变量 $VAR会被解析,但命令替换 ` `或 $( )仍生效)。
九、实战示例
示例1:显示系统信息脚本(OS.sh)
#!/bin/bash
RED="\E[1;31m"
GREEN="\E[1;32m"
END="\E[0m"
echo -e "${GREEN}----------Host systeminfo----------${END}"
echo -e "HOSTNAME: ${RED}$(hostname)${END}"
echo -e "IPADDR: ${RED}$(ifconfig ens160 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -n1)${END}"
echo -e "OSVERSION: ${RED}$(cat /etc/redhat-release)${END}"
echo -e "KERNEL: ${RED}$(uname -r)${END}"
echo -e "CPU: ${RED}$(lscpu | grep "型号名称:" | tr -s ' ' ' '|cut -d ' ' -f 2-5)${END}"
echo -e "MEMORY: ${RED}$(free -h | grep Mem | tr -s ' ' ' '|cut -d ' ' -f 4)${END}"
echo -e "DISK: ${RED}$(lsblk | grep '^sda' | tr -s ' ' | cut -d ' ' -f 4)${END}"
echo -e "${GREEN}---------- END ----------${END}"
运行:chmod +x OS.sh && ./OS.sh
示例2:通过变量动态执行命令
CMD=hostname
$CMD # 实际执行 hostname 命令,输出当前主机名
十、总结
•
变量是Shell脚本的核心:合理使用变量能让脚本更灵活、可维护。
•
命名规范是关键:遵循规则(如避免数字开头、用有意义的名字)减少错误。
•
作用域决定使用场景:普通变量用于脚本内部,环境变量用于跨进程传递信息。
•
特殊变量(如 $1、$?)是脚本交互的基础:掌握它们才能编写实用的参数处理和错误判断逻辑。