第 32 课:Shell 变量与数据类型
学习目标
通过本课学习,你将能够:
- 理解 Shell 变量的概念,并能正确定义和使用变量。
- 区分 Shell 中的基本数据类型(主要是字符串和整数)。
- 掌握 Shell 脚本中常用的特殊变量及其用途。
- 能够在 Shell 脚本中进行基本的整数运算和字符串操作。
- 综合运用变量编写简单的自动化脚本。
核心概念
1. 变量是什么?
你可以把变量想象成一个带标签的盒子。盒子用来存放东西(数据),标签就是变量的名字。在 Shell 中,我们通过变量名来存取和操作数据。
关键点:
- 定义与赋值:使用
变量名=值的语法。注意:等号=两边不能有空格! - 使用变量:在变量名前加上
$符号来获取其值。 - 命名规则:以字母或下划线开头,可以包含字母、数字和下划线。建议使用有意义的名称,如
file_count、user_name。
# 定义一个变量 greeting,并赋值 “Hello”
greeting=Hello
echo $greeting # 输出: Hello
# 定义一个存储数字的变量
count=10
echo “There are $count items.” # 输出: There are 10 items.
2. 数据类型:字符串与整数
Bash 中的变量默认都是字符串类型。即使你存储的是数字,它也被视为字符序列。只有在需要时(比如进行数学运算),Bash 才会尝试将它们当作整数处理。
- 字符串:用单引号
' '或双引号" "包裹。两者的主要区别在于:- 单引号:所见即所得,内部任何字符都保持原样。
- 双引号:可以解析其中的变量(
$var)和转义字符(\n)。
- 整数:当变量被用于算术运算时,Bash 会尝试将其值解释为整数。如果字符串内容不是合法的数字,运算会失败。
# 字符串变量
name=’John Doe‘ # 包含空格,必须用引号
sentence="My name is $name." # 双引号内,变量 $name 被解析
echo $sentence # 输出: My name is John Doe.
# 整数与字符串的对比
num=10 # 这是一个内容为”10“的字符串变量
echo $num # 输出: 10
# 直接进行算术运算(稍后详解),Bash会将其作为整数处理
result=$((num + 5))
echo $result # 输出: 15
3. 特殊变量
Bash 脚本提供了一些预定义的特殊变量,它们在处理脚本参数和状态时非常有用。
| 变量 | 含义 |
|---|---|
$0 | 脚本自身的名称 |
$1, $2, $3… | 传递给脚本的第1个、第2个、第3个参数… |
$# | 传递给脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数(如 “$1 $2 $3”) |
$@ | 与 $* 类似,但每个参数都作为独立的字符串(如 “$1” “$2” “$3”) |
$? | 上一个命令的退出状态码(0表示成功,非0表示失败) |
$$ | 当前脚本的进程ID (PID) |
#!/bin/bash
# 这个脚本演示特殊变量
echo “脚本名: $0”
echo “第一个参数: $1”
echo “第二个参数: $2”
echo “参数总数: $#”
echo “所有参数: $@”
将上述脚本保存为 test_args.sh,并运行 ./test_args.sh apple banana,你会看到相应信息的输出。
4. 数值运算
Bash 支持基本的整数运算。语法是 $((表达式))。
a=100
b=20
sum=$((a + b))
diff=$((a - b))
prod=$((a * b))
quot=$((a / b)) # 注意:这是整除,结果为5
echo “和: $sum, 差: $diff, 积: $prod, 商: $quot”
注意:Bash 原生不支持浮点数运算。如需计算小数,需借助 bc、awk 等外部工具。
5. 字符串操作
Bash 提供了一些便捷的字符串操作语法:
str=“Hello, World!”
# 获取字符串长度
len=${#str}
echo “长度: $len” # 输出: 13
# 截取子串 (从位置0开始,截取5个字符)
sub=${str:0:5}
echo “子串: $sub” # 输出: Hello
# 替换第一次出现的匹配
new_str=${str/World/Bash}
echo “替换后: $new_str” # 输出: Hello, Bash!
代码示例
一个综合示例:编写一个脚本,接收一个文件名作为参数,打印其行数、单词数和字符数,并检查文件是否存在。
#!/bin/bash
# 脚本名:file_info.sh
# 功能:统计指定文件的行数、单词数和字符数
# 检查是否提供了文件名参数
if [ $# -eq 0 ]; then
echo “错误:请提供一个文件名作为参数。”
echo “用法: $0 <文件名>”
exit 1 # 非零退出码表示错误
fi
# 将第一个参数赋值给变量 file
file=$1
# 检查文件是否存在且可读
if [ ! -f “$file” ]; then
echo “错误:文件 ‘$file’ 不存在或不是一个普通文件。”
exit 1
fi
# 使用 wc 命令获取文件信息,并通过 cut 命令提取特定字段
lines=$(wc -l < “$file”)
words=$(wc -w < “$file”)
chars=$(wc -m < “$file”)
# 输出结果
echo “文件信息: $file”
echo “行数: $lines”
echo “单词数: $words”
echo “字符数: $chars”
实践练习
练习 1:基础变量与输出
编写一个脚本 greet.sh,它接收一个名字作为第一个参数(例如 ./greet.sh Alice),输出 “Hello, Alice! Welcome to the Shell world.”。如果未提供参数,则输出 “Hello, World! Welcome to the Shell world.”。
预期输出:
./greet.sh Alice
Hello, Alice! Welcome to the Shell world.
./greet.sh
Hello, World! Welcome to the Shell world.
练习 2:数值运算与字符串拼接
编写一个脚本 calc_area.sh,它接收两个数字作为参数,分别代表长方形的长和宽(例如 ./calc_area.sh 10 5)。脚本应计算并输出 “The area of a rectangle with length 10 and width 5 is 50.”。
预期输出:
./calc_area.sh 10 5
The area of a rectangle with length 10 and width 5 is 50.
练习 3:综合挑战
编写一个脚本 param_counter.sh。它接收任意数量的参数。脚本需要:
- 输出参数的总数。
- 使用
for循环遍历所有参数,并输出每个参数及其序号(从1开始)。 - 最后,输出这些参数拼接后的字符串(参数之间用
,分隔)。
预期输出示例(运行 ./param_counter.sh apple banana cherry):
Total parameters: 3
Parameter 1: apple
Parameter 2: banana
Parameter 3: cherry
All parameters: apple, banana, cherry
常见错误
-
赋值时等号两边加空格
- 错误:
name = “John”(会尝试运行一个叫name的命令,并将=和"John"作为参数)。 - 正确:
name=“John”(等号两边没有空格)。
- 错误:
-
使用变量时忘记
$- 错误:
echo name(会输出字符串 “name”)。 - 正确:
echo $name(会输出变量name的值)。
- 错误:
-
字符串中变量解析混乱
- 意图:
echo “Price is $5”(想输出Price is $5)。 - 实际:Bash 会尝试解析
$5,这是一个未定义的变量,可能输出Price is。 - 解决:使用单引号
echo ‘Price is $5’或转义$echo “Price is \$5”。
- 意图:
-
对非数字字符串进行算术运算
- 错误:
val=abc; result=$((val + 1))(会导致语法错误或意外结果)。 - 正确:在进行运算前确保变量包含有效数字。
- 错误:
-
特殊变量
$*和$@在未加引号时行为相同- 当被双引号包围时,它们的行为不同。
“$*”将所有参数视为一个整体字符串,而“$@”则保留每个参数的独立性。在遍历参数时,通常推荐使用“$@”。
- 当被双引号包围时,它们的行为不同。
小结
本节课我们学习了 Shell 脚本编程中最基础的部分:
- 变量是存储数据的容器,使用
name=value定义,$name使用。 - Bash 中变量主要作为字符串处理,通过
$((...))进行整数运算。 - 特殊变量(如
$1,$#,$@)是处理脚本参数和流程控制的关键。 - 可以进行常见的字符串操作,如获取长度
${#str}、截取${str:pos:len}和替换${str/old/new}。 - 在编写脚本时,要养成良好的习惯:检查参数、进行错误处理、为变量使用清晰的名字。
掌握了变量和数据类型,你就拥有了让 Shell 脚本“活”起来的基础能力。下一课我们将深入探讨环境变量,了解变量在父子 Shell 之间传递的奥秘。