数据类型 #
一、Shell数据类型概述 #
Shell是一种弱类型语言,变量不需要预先声明类型。Shell主要支持以下数据类型:
| 类型 | 说明 | 示例 |
|---|---|---|
| 字符串 | 文本数据 | “hello” |
| 数字 | 整数运算 | 123 |
| 数组 | 数据集合 | (a b c) |
| 关联数组 | 键值对 | ([key]=value) |
二、字符串 #
2.1 字符串定义 #
bash
# 单引号字符串
str1='Hello World'
# 双引号字符串(支持变量替换)
name="张三"
str2="你好, $name"
# 无引号字符串(不推荐)
str3=Hello
# 多行字符串
str4="第一行
第二行
第三行"
# Here Document
str5=$(cat <<EOF
这是多行文本
可以包含变量: $name
EOF
)
2.2 单引号与双引号 #
bash
name="张三"
# 单引号:原样输出
echo '你好, $name' # 输出: 你好, $name
# 双引号:变量替换
echo "你好, $name" # 输出: 你好, 张三
# 转义字符
echo "换行\n制表\t" # 输出: 换行\n制表\t
echo -e "换行\n制表\t" # 输出: 换行
# 制表
2.3 字符串操作 #
bash
str="Hello World"
# 获取长度
echo ${#str} # 输出: 11
# 拼接字符串
str1="Hello"
str2="World"
result="${str1} ${str2}"
echo "$result" # 输出: Hello World
# 截取子串
str="Hello World"
echo ${str:0:5} # 输出: Hello
echo ${str:6} # 输出: World
echo ${str: -5} # 输出: World(注意空格)
# 查找子串
str="Hello World"
echo ${str#Hello} # 输出: World
echo ${str%World} # 输出: Hello
2.4 字符串替换 #
bash
str="hello world world"
# 替换第一个匹配
echo ${str/world/WORLD} # 输出: hello WORLD world
# 替换所有匹配
echo ${str//world/WORLD} # 输出: hello WORLD WORLD
# 删除匹配
echo ${str//world/} # 输出: hello
# 从开头删除
str="hello.txt"
echo ${str%.txt} # 输出: hello
# 从结尾删除
str="/path/to/file.txt"
echo ${str##*/} # 输出: file.txt
三、数字 #
3.1 整数 #
Shell原生只支持整数运算:
bash
# 定义整数
num=42
# 算术运算
echo $((num + 10)) # 输出: 52
echo $((num - 10)) # 输出: 32
echo $((num * 2)) # 输出: 84
echo $((num / 5)) # 输出: 8
echo $((num % 5)) # 输出: 2
# 自增自减
count=0
((count++))
echo $count # 输出: 1
((count--))
echo $count # 输出: 0
3.2 算术运算方式 #
bash
# 方式一:$(())
result=$((5 + 3))
echo $result # 输出: 8
# 方式二:let
let result=5+3
echo $result # 输出: 8
# 方式三:expr
result=$(expr 5 + 3)
echo $result # 输出: 8
# 方式四:bc(支持浮点)
result=$(echo "5.5 + 3.3" | bc)
echo $result # 输出: 8.8
3.3 浮点数运算 #
Shell原生不支持浮点数,需要使用bc或awk:
bash
# 使用bc
result=$(echo "scale=2; 10 / 3" | bc)
echo $result # 输出: 3.33
# 使用awk
result=$(awk 'BEGIN{printf "%.2f", 10/3}')
echo $result # 输出: 3.33
# 比较浮点数
a=3.14
b=3.15
if (( $(echo "$a < $b" | bc -l) )); then
echo "$a 小于 $b"
fi
3.4 数字进制 #
bash
# 二进制
binary=2#1010
echo $binary # 输出: 10
# 八进制
octal=8#12
echo $octal # 输出: 10
# 十六进制
hex=16#A
echo $hex # 输出: 10
# 进制转换
echo $((16#FF)) # 输出: 255
echo "obase=2; 10" | bc # 输出: 1010
四、数组 #
4.1 普通数组 #
bash
# 定义数组
arr=(1 2 3 4 5)
# 访问元素
echo ${arr[0]} # 输出: 1
echo ${arr[2]} # 输出: 3
# 所有元素
echo ${arr[@]} # 输出: 1 2 3 4 5
echo ${arr[*]} # 输出: 1 2 3 4 5
# 数组长度
echo ${#arr[@]} # 输出: 5
# 添加元素
arr+=(6 7)
echo ${arr[@]} # 输出: 1 2 3 4 5 6 7
# 删除元素
unset arr[2]
echo ${arr[@]} # 输出: 1 2 4 5 6 7
4.2 数组操作 #
bash
# 定义数组
arr=(apple banana cherry date)
# 遍历数组
for item in "${arr[@]}"; do
echo "水果: $item"
done
# 带索引遍历
for i in "${!arr[@]}"; do
echo "索引 $i: ${arr[$i]}"
done
# 切片
echo ${arr[@]:1:2} # 输出: banana cherry
# 查找元素
if [[ " ${arr[@]} " =~ " banana " ]]; then
echo "找到banana"
fi
# 数组拼接
arr1=(1 2 3)
arr2=(4 5 6)
arr3=("${arr1[@]}" "${arr2[@]}")
echo ${arr3[@]} # 输出: 1 2 3 4 5 6
4.3 关联数组 #
bash
# 声明关联数组
declare -A user
# 设置键值对
user[name]="张三"
user[age]=25
user[city]="北京"
# 访问元素
echo ${user[name]} # 输出: 张三
echo ${user[age]} # 输出: 25
# 所有键
echo ${!user[@]} # 输出: name age city
# 所有值
echo ${user[@]} # 输出: 张三 25 北京
# 遍历
for key in "${!user[@]}"; do
echo "$key: ${user[$key]}"
done
# 数组长度
echo ${#user[@]} # 输出: 3
五、类型判断与转换 #
5.1 类型判断 #
bash
# 判断是否为数字
is_number() {
[[ "$1" =~ ^[0-9]+$ ]]
}
is_number "123" && echo "是数字"
is_number "abc" || echo "不是数字"
# 判断是否为整数
is_integer() {
[[ "$1" =~ ^-?[0-9]+$ ]]
}
# 判断是否为浮点数
is_float() {
[[ "$1" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]
}
5.2 字符串转数字 #
bash
# 字符串转整数
str="123"
num=$((str))
echo $num # 输出: 123
# 使用expr
num=$(expr "$str" + 0)
# 使用bc
float_str="3.14"
float_num=$(echo "$float_str" | bc)
echo $float_num # 输出: 3.14
5.3 数字转字符串 #
bash
# 数字本身就是字符串形式
num=123
str="$num"
echo $str # 输出: 123
# 格式化输出
num=42
str=$(printf "%05d" $num)
echo $str # 输出: 00042
六、特殊数据结构 #
6.1 只读变量 #
bash
# 声明只读变量
readonly PI=3.14159
# 或
declare -r PI=3.14159
# 尝试修改会报错
PI=3.14 # 报错: PI: readonly variable
6.2 整数变量 #
bash
# 声明整数变量
declare -i count
count=10
count="hello" # 自动转换为0
echo $count # 输出: 0
# 整数变量自动计算
declare -i num
num=5+3
echo $num # 输出: 8
6.3 数组变量 #
bash
# 声明数组
declare -a arr
arr=(1 2 3)
# 声明关联数组
declare -A map
map[key]=value
6.4 导出变量 #
bash
# 声明并导出
declare -x MY_VAR="value"
# 等同于
export MY_VAR="value"
七、实战示例 #
7.1 配置文件解析 #
bash
#!/bin/bash
# 配置文件格式: key=value
parse_config() {
local config_file="$1"
declare -A config
while IFS='=' read -r key value; do
# 跳过注释和空行
[[ "$key" =~ ^#.*$ || -z "$key" ]] && continue
# 去除前后空格
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
config["$key"]="$value"
done < "$config_file"
# 返回配置
for key in "${!config[@]}"; do
echo "$key=${config[$key]}"
done
}
parse_config "config.conf"
7.2 数据处理脚本 #
bash
#!/bin/bash
# 处理CSV数据
process_csv() {
local csv_file="$1"
declare -a headers
declare -a rows
# 读取表头
IFS=',' read -ra headers <<< "$(head -n 1 "$csv_file")"
# 读取数据行
while IFS=',' read -ra row; do
rows+=("$(IFS=','; echo "${row[*]}")")
done < <(tail -n +2 "$csv_file")
# 显示数据
echo "表头: ${headers[*]}"
echo "行数: ${#rows[@]}"
}
process_csv "data.csv"
7.3 类型安全函数 #
bash
#!/bin/bash
# 类型安全的加法函数
safe_add() {
local a="$1"
local b="$2"
# 验证输入
if ! [[ "$a" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then
echo "错误: $a 不是有效数字" >&2
return 1
fi
if ! [[ "$b" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then
echo "错误: $b 不是有效数字" >&2
return 1
fi
# 执行加法
echo "$a + $b" | bc
}
safe_add "3.14" "2.86"
八、总结 #
8.1 数据类型要点 #
| 类型 | 说明 | 操作 |
|---|---|---|
| 字符串 | 文本数据 | ${#str}, $ |
| 数字 | 整数 | $(()), let, expr |
| 数组 | 索引数组 | ${arr[@]}, $ |
| 关联数组 | 键值对 | declare -A, $ |
8.2 类型声明 #
bash
declare -r var=value # 只读
declare -i var=value # 整数
declare -a var=() # 数组
declare -A var=() # 关联数组
declare -x var=value # 导出
8.3 下一步 #
你已经掌握了Shell的数据类型,接下来让我们学习 算术运算符,深入了解Shell中的运算操作!
最后更新:2026-03-27