Shell脚本编程——变量用法详解

一、变量基础概念

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、$?)是脚本交互的基础​:掌握它们才能编写实用的参数处理和错误判断逻辑。