Shell 脚本编程中,变量是最基础也是最重要的概念。一个固定的字符串去表示不固定的内容,让脚本变得灵活、可复用。
本文将系统讲解 Shell 变量的定义、引用、运算、环境变量、位置变量,并通过实战案例带你掌握变量的正确使用方法。
简介

什么是 Shell
Shell 是命令解释器,一种应用程序。它是用户使用 Linux 的桥梁,用户的大部分工作都是通过 Shell 完成的。
Shell 语言的特点:
- Shell 语言是指 UNIX 操作系统的命令语言,同时也是该命令语言的解释程序的简称
- Shell 本身是一个用 C 语言编写的程序
- Shell 既是一种命令语言,又是一种程序设计语言
- 作为命令语言,它交互式地解释和执行用户输入的命令
- 作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支
- 它虽然不是 Linux 系统内核的一部分,但它调用了系统核心的大部分功能来执行程序、建立文件并以并行的方式协调各个程序的运行
- 对于用户来说,shell 是最重要的实用程序
Shell 能做什么
| 场景 | 示例 |
|---|---|
| 自动化系统初始化 | update、软件安装、时区设置、安全策略 |
| 自动化软件部署 | LAMP、LNMP、Tomcat、LVS、Nginx |
| 应用管理 | KVM、集群管理扩容、MySQL、DELL R720 批量 RAID |
| 日志分析处理 | PV、UV、200 代码、top 100、grep/awk |
| 自动化备份恢复 | MySQL 完全备份/增量 + Crond |
| 自动化管理 | 批量远程修改密码、软件升级、配置更新 |
| 信息采集及监控 | 收集系统/应用状态信息,CPU、Mem、Disk、Net、TCP Status |
| 配合 Zabbix 采集 | 收集系统/应用状态信息,CPU、Mem、Disk、Net |
| 自动化扩容 | 增加云主机 → 业务上线 |
| 趣味编程 | 俄罗斯方块、打印三角形、打印圣诞树、排序算法 |
Shell 执行方式
准备测试脚本:
[root@localhost]# vim file1
echo "hello 1234"
read -p "请输入您的姓名:" name
echo "哈哈 $name 是大笨蛋"
四种执行方式:
| 执行方式 | 命令 | 运行环境 |
|---|---|---|
| 方式 1 | bash file1 | 子 Shell |
| 方式 2 | sh file1 | 子 Shell(which bash 和 which sh 发现是同一个文件) |
| 方式 3 | . file1 | 当前 Shell |
| 方式 4 | source file1 | 当前 Shell(同方式 3) |
子 Shell vs 当前 Shell 的区别:
# 准备环境
[root@localhost ~]# vim bash.sh
#!/usr/bin/bash
cd /home/
ls
# 分别使用当前Shell和子 Shell 执行(. bash.sh 或 source bash.sh)
[root@localhost ~]# bash bash.sh
[root@localhost ~]#
[root@localhost ~]# . bash.sh
[root@localhost home]#
# 观察:当前shell让目录改变了
关键区别:
bash和sh是在子 Shell 中执行,不影响当前环境;.和source是在当前 Shell 中执行,用于影响当前 Shell 环境(如修改目录、设置变量等)。
Shell 解释器位置
# 查看系统支持的 Shell
[root@localhost home]# cat /etc/shells
# 或使用
[root@localhost ~]# chsh -l
自定义变量
什么是 Shell 变量
Shell 变量:用一个固定的字符串去表示不固定的内容,便于修改。
变量基本操作
| 操作 | 语法 | 示例 |
|---|---|---|
| 定义变量 | 变量名=变量值 | name="zhangsan 666" |
| 引用变量 | $变量名 或 ${变量名} | echo $name |
| 查看变量 | echo $变量名 | echo $name |
| 查看所有变量 | set | set(包括自定义变量和环境变量) |
| 取消变量 | unset 变量名 | unset name |
正确定义变量
[root@localhost ~]# name="zhangsan 666"
[root@localhost ~]# echo $name
zhangsan 666
错误定义示范
# 错误 1:变量名不能以数字开头
[root@localhost ~]# 2name="lisi 666"
-bash: 2name=lisi 666: command not found
# 错误 2:等号左右两侧不能有空格
[root@localhost ~]# name = "lisi 666"
-bash: name: command not found
# 错误 3:变量的值如果有空格,必须用引号包含
[root@localhost ~]# name=lisi 666
-bash: 666: command not found
变量命名规则
- 命名只能使用英文字母、数字和下划线
- 首个字符不能以数字开头
- 中间不能有空格,可以使用下划线(
_) - 不能使用标点符号
- 不能使用 bash 里的关键字(可用
help命令查看保留关键字) - 建议变量名使用五个字母以上
重复定义变量(变量叠加)
# 定义变量 aa 的值是 123
[root@localhost ~]# aa=123
# 重复定义:原 aa 的值加上 456
[root@localhost ~]# aa="$aa"456
# 调用变量 aa,发现值已经变成了 123456
[root@localhost ~]# echo $aa
123456
# 在进行变量叠加时,也可以使用 ${变量名} 格式
[root@localhost ~]# aa=${aa}789
[root@localhost ~]# echo $aa
123456789
注意:在进行变量叠加时,变量名需要用双引号或
${}包含。
变量调用示例
准备一台虚拟机:IP为192.168.100.10
使用变量前:
[root@localhost ~]# vim ping.sh
# 需求:编写测试主机在线的脚本
# 当主机在线提示在线,当主机不在线提示不在线
ping -c1 192.168.100.10 &>/dev/null && echo 192.168.100.10 up || echo 192.168.100.10 down
输出示例
# 192.168.100.10未开机
[root@localhost ~]# bash ping.sh
192.168.100.10 down
# 192.168.10.10开机
[root@localhost ~]# bash ping.sh
192.168.100.10 up
问题:如果更换测试 IP,需要修改脚本中的三个部分(ping 目标、echo up、echo down)。
使用变量后:
[root@localhost ~]# vim ping.sh
#!/bin/bash
ip=192.168.100.10
ping -c1 $ip &>/dev/null && echo $ip up || echo "$ip down"
# 授权脚本(加执行权限)
[root@localhost ~]# chmod +x ping.sh
# 执行脚本
[root@localhost ~]# ./ping.sh
优势:添加变量后,更换 IP 只需修改一处即可。
三目表达式说明:
| 符号 | 含义 |
|---|---|
&& | 前面的命令成功(返回 0),执行后面的命令 |
| ` |
交互定义变量(read)
read命令:从键盘读入变量值。
语法:
read 变量名
read -p "提示信息" 变量名
示例:
[root@localhost ~]# read -p "请输入您测试的IP地址:" ip
请输入您测试的IP地址:192.168.100.100
[root@localhost ~]# echo $ip
192.168.100.100
三种引号的区别
| 引号 | 类型 | 说明 |
|---|---|---|
" " | 弱引用 | 转义大部分符号,但 $、`、\ 仍保持特殊含义 |
' ' | 强引用 | 转义一切符号 |
` ` | 命令替换 | 优先执行内部的命令 |
双引号示例 1:
# 错误示范:shell 把空格识别为命令分隔符
[root@localhost ~]# schoo=1000 phone
-bash: phone: command not found
# 正确示范:变量值中的空格被转义为一个普通符号
[root@localhost ~]# schoo="1000 phone"
[root@localhost ~]# echo $schoo
1000 phone
双引号示例 2:
# 错误示范:已有变量的基础上再追加内容
[root@localhost ~]# schoo=$schoo is good
-bash: is: command not found
# 没有加引号,被识别为两条命令
# 正确示范:加了双引号,组成整体,空格失去含义
[root@localhost ~]# schoo="$schoo is good"
[root@localhost ~]# echo $schoo
1000 phone is good
单引号示例:
[root@localhost ~]# schoo='$schoo 666'
# 单引号,转义一切符号
[root@localhost ~]# echo $schoo
$schoo 666
# $ 也被转义了,一切都被转义了
反引号示例:
[root@localhost ~]# schoo=`date`
# 反引号是优先执行:先执行 date 的命令,再执行定义变量
[root@localhost ~]# echo $schoo
Thu Jun 4 18:09:28 CST 2026
# 所以看到变量的结果,是时间
反引号
`command`等价于$(command),推荐使用$()语法,更易读。
整数运算
方法一:expr
# 语法
expr 1 + 2
expr $num1 + $num2
# 运算符:+(加)、-(减)、\*(乘,* 是任意字符,使用 \ 转义)、/(除)、%(取余)
示例:
[root@localhost ~]# num1=9
[root@localhost ~]# num2=10
[root@localhost ~]# expr $num1 + $num2
19
案例:计算学员成绩总分
[root@localhost ~]# vim sum.sh
#!/bin/bash
read -p "请输入您的第一门成绩: " number1
read -p "请输入您的第二门成绩: " number2
echo -n "总成绩是: "
expr $number1 + $number2
[root@localhost ~]# chmod +x sum.sh
[root@localhost ~]# bash sum.sh
请输入您的第一门成绩: 12
请输入您的第二门成绩: 99
总成绩是: 111
方法二:$(())
# 语法
echo $(($num1 + $num2))
echo $((num1 + num2)) # 可以省略 $
echo $((5 - 3 * 2)) # 结果为 -1
echo $((2 ** 3)) # 幂运算:2 的 3 次方,结果为 8
方法三:$[]
# 语法
echo $[5 + 2] # + - * / %
echo $[5 ** 2] # 幂运算:25
方法四:let
# 示例
let sum=2+3; echo $sum # 输出 5
let i++; echo $i # 自增
四种运算方式对比:
| 方法 | 语法 | 支持幂运算 | 说明 |
|---|---|---|---|
expr | expr 1 + 2 | 不支持 | 需要空格分隔,乘号需转义 |
$(()) | echo $((1+2)) | 支持 ** | 推荐,语法简洁 |
$[] | echo $[1+2] | 支持 ** | 较老的语法 |
let | let sum=1+2 | 支持 ** | 适合变量赋值 |
小数运算(了解)
需要安装计算器程序
bc。
# 安装 bc
yum -y install bc
# 基本运算
echo "2 * 4" | bc # 输出 8
echo "2 ^ 4" | bc # 输出 16(幂运算)
echo "scale=2; 6 / 4" | bc # 输出 1.50(保留两位小数)
| 参数 | 说明 |
|---|---|
bc | 交互式运算器 |
scale=2 | 保留小数点后两位 |
环境变量(了解)
前言
自定义变量只能在当前 Shell 中生效,其他 Shell 是不生效的。说白了,你的变量只能你用。那如果有些变量,需要所有的用户都使用,怎么办呢?
定义环境变量
| 方法 | 语法 | 说明 |
|---|---|---|
| 直接声明 | export back_dir2=/home/backup | 直接声明环境变量 |
| 转换声明 | export back_dir1 | 将已有的自定义变量转换成环境变量 |
变量作用范围:在当前 Shell 和子 Shell 有效。
持久化环境变量
| 文件 | 作用范围 | 说明 |
|---|---|---|
~/.bash_profile | 当前用户 | 当前用户登录后一直生效 |
/etc/profile | 所有用户 | 所有用户登录后一直生效 |
示例
# 定义普通变量 1
[root@localhost ~]# abc=123
# 定义普通变量 2
[root@localhost ~]# def=456
# 打开子 Shell
[root@localhost ~]# bash
# 调用普通变量,失败
[root@localhost ~]# echo $abc
(空)
[root@localhost ~]# echo $def
(空)
# 退出子 Shell
[root@localhost ~]# exit
# 将变量声明为环境变量(儿子 Shell 都能用)
[root@localhost ~]# export abc
# 打开子 Shell
[root@localhost ~]# bash
# 发现变量可以用了
[root@localhost ~]# echo $abc
123
# 普通变量还是不行
[root@localhost ~]# echo $def
(空)
位置变量和预定义变量(了解)
位置变量
位置变量用于在脚本中接收用户传入的参数。
语法:
命令 参数1 参数2 参数3 ...
$0 $1 $2 $3 ...
| 变量 | 说明 |
|---|---|
$0 | 脚本名/程序名 |
$1 ~ $9 | 第 1 到第 9 个参数 |
$10 以后 | 需要用 ${10} 格式 |
示例:计算两门学科的平均分
[root@localhost ~]# vim avg.sh
#!/bin/bash
echo "($1+$2)/2" | bc
[root@localhost ~]# chmod +x avg.sh
# 测试脚本
[root@localhost ~]# ./avg.sh 88 77
82
预定义变量
| 变量 | 说明 |
|---|---|
$0 | 脚本名/程序名 |
$* | 所有的参数 |
$# | 参数的个数 |
$? | 上一个命令的返回值(0 是成功,非零失败) |
$$ | 程序的 PID |
示例:
[root@localhost ~]# vim avg.sh
#!/bin/bash
echo "($1+$2)/2" | bc
echo "该程序名为 $0"
echo "该程序使用了 $# 个参数"
echo "该程序的参数如下:$*"
[root@localhost ~]# ./avg.sh 60 50
55
该程序名为 ./avg.sh
该程序使用了 2 个参数
该程序的参数如下:60 50
总结:
- 位置变量就是
$1、$2、$3、$4…- 位置变量预先已经被定义好了
- 用户使用时,必须携带参数
- 位置变量不是程序设计的唯一方法,
read也可以
位置变量 vs read
两种方法都可以实现参数输入:
#!/bin/bash
read -p "请输入您的第1门成绩: " num1
read -p "请输入您的第2门成绩: " num2
echo -n "您的平均成绩是:"
echo "($num1+$num2)/2" | bc
| 方式 | 特点 | 适用场景 |
|---|---|---|
| 位置变量 | 参数直接跟在命令后面 | 适合命令行快捷调用 |
| read | 交互式输入,有提示信息 | 适合需要引导用户输入的场景 |
实战案例
案例 1:自动创建用户并设置初始密码为123456
#!/bin/bash
read -p "please input username: " name
useradd $name
echo "123456" | passwd --stdin $name &>/dev/null
echo "$name create finished, the password is 123456"
执行效果:
[root@localhost ~]# bash create_user.sh
please input username: abcdefg
abcdefg create finished, the password is 123456
案例 2:配置本地 YUM 源
#!/bin/bash
# 挂载光盘
mount /dev/cdrom /mnt &>/dev/null
# 删除原有仓库配置
rm -rf /etc/yum.repos.d/*
# 创建新的 YUM 仓库配置
cat << EOF > /etc/yum.repos.d/yum.repo
[local]
name=localyum baseurl=file:///mnt enabled=1 gpgcheck=0 EOF # 检查仓库列表 yum repolist all
常见问题
变量定义时报错 “command not found”
检查等号两侧是否有多余的空格。在 Shell 中,= 两侧不能有空格。
变量值中有空格怎么处理
使用双引号包裹变量值:name="hello world"。
变量在子 Shell 中无法使用
使用 export 将变量声明为环境变量:export 变量名。
如何让变量永久生效
- 当前用户永久生效:将变量写入
~/.bash_profile - 所有用户永久生效:将变量写入
/etc/profile
最佳实践
变量名命名规范
- 使用下划线分隔单词:
db_password而非dbpassword - 变量名至少五个字母以上
- 避免使用关键字和保留字
- 使用下划线分隔单词:
引号使用原则
- 字符串赋值时使用双引号:
name="hello world" - 需要完全转义时使用单引号:
path='$HOME/test' - 命令执行使用
$():date=$(date)
- 字符串赋值时使用双引号:
变量叠加使用
${}path="${path}:/usr/local/bin"整数运算优先使用
$(())echo $(($a + $b))使用
$?检查命令是否成功[root@localhost ~]# ls /home/
abcdefg
[root@localhost ~]# echo $?
0
[root@localhost ~]# ls /home/aaa
ls: cannot access /home/aaa: No such file or directory
[root@localhost ~]# echo $?
2
总结
通过本章节的学习,你应该掌握了:
- 理解 Shell 的概念、特点和作用
- 掌握 Shell 的四种执行方式(bash、sh、.、source)及区别
- 掌握自定义变量的定义、引用、查看、删除操作
- 理解变量命名规则和错误定义示范
- 掌握变量叠加的正确方法
- 理解三种引号的区别(双引号、单引号、反引号)
- 掌握四种整数运算方法(expr、$(())、$[]、let)
- 了解小数运算(bc)
- 理解环境变量和自定义变量的区别
- 掌握环境变量的定义方法和持久化方式
- 掌握位置变量($0 ~ $9)和预定义变量($*、$#、$?、$$)
- 能够编写自动创建用户和配置 YUM 源的脚本
学习建议:Shell 变量是 Shell 编程的基础。建议在虚拟机上动手练习每一个示例,特别是三种引号的区别和四种运算方式。变量叠加和位置变量是编写实用脚本的关键,务必熟练掌握。