Skip to content

变量与数据类型:字符串、数字、数组

Shell 里一切以字符串处理居多,算术、数组、关联数组则各有约定写法。


一、变量基础

Shell 变量是在 Shell 环境中存储数据的命名容器,用于在脚本或交互会话里传递和操作数据。

定义与赋值

shell
变量名=变量值

# 示例
name="David"
readonly age=18   # 只读,后续不可改

# 注意
# - 等号两侧不能有空格
# - 变量名只能包含字母、数字、下划线,且不能以数字开头
# - 值含空格时必须引号括起来;纯字符串且无空格时有时可省略引号,但不推荐依赖省略

读取变量

shell
echo $name
echo ${name}    # 推荐:边界清晰

# 拼接时 ${name} 更安全,例如:
echo "Hello, ${name}Script"

删除变量

shell
unset name

默认值与兜底(兼容性常用)

shell
${变量名:-默认值}   # 未定义或为空时返回默认值,不赋值
${变量名:=默认值}   # 未定义或为空时赋默认值并返回

echo ${name:-"Unknown"}

环境变量与局部变量

环境变量:被子进程继承;常用 export

shell
export PATH=$PATH:/新路径
export LANG=en_US.UTF-8

env
printenv
set              # 所有变量(含 shell 选项)
set -u           # 使用未定义变量时报错,避免默默为空

局部变量(函数内):

shell
my_func() {
    local x=10
    echo $x
}

常用内置/环境相关变量

shell
$HOME    # 用户主目录
$PWD     # 当前工作目录
$USER    # 当前用户
$SHELL   # 当前 Shell 路径
$PATH    # 命令搜索路径
$?       # 上条命令退出码
$$       # 当前进程 ID
$0       # 脚本名
$1...    # 参数
$#       # 参数个数
$* / $@  # 全部参数

二、字符串

包括:定义、长度、拼接、截取、替换、删除、子串判断、大小写。

单引号、双引号

  • 单引号 '':强引用,不展开变量、不解释多数转义(单引号内不能再写单引号作为内容,需换写法)。
  • 双引号 "":弱引用,会展开变量、命令替换与部分转义。
shell
name="world"
str='hello $name'    # 字面量 hello $name
str2="hello $name"   # hello world

长度、拼接

shell
str="test"
echo ${#str}         # 4

first="Hello"
last="World"
echo "$first$last"
echo "$first $last"   # 含空格时务必加引号

截取 ${var:offset:length}

索引从 0 开始;从末尾数可用负数,负索引前建议加空格,避免与默认值的 :- 语法冲突。

shell
str="abcdefghij"
echo ${str:2}        # 从索引 2 到末尾
echo ${str:3:4}      # 从 3 起 4 个字符
echo ${str: -2}      # 最后两个字符(注意 -2 前空格)

替换

shell
str="apple banana apple cherry"

# 只换第一个
echo ${str/apple/APPLE}
# 全部替换
echo ${str//apple/APPLE}
# 行首/行尾
echo ${str/#apple/FRUIT}
echo ${str/%cherry/FRUIT}
# 删成空
echo ${str//banana/}

删前缀/后缀(# ## % %%

shell
file_path="/home/user/documents/report.txt"
echo ${file_path##*/}     # 文件名:report.txt
echo ${file_path%.txt}    # 去最后一个 .txt
echo ${file_path%/*}      # 目录部分
echo ${file_path#/home/}  # 去最短前缀 /home/

是否包含子串、查位置

shell
# 是否包含(Bash [[ ]]
[[ $str == *子串* ]]

# 位置:expr
expr index "$str" 子串

# 或 awk
awk -v str="$str" -v sub="world" 'BEGIN{print index(str, sub)}' </dev/null

大小写(借助 tr / awk)

shell
str="Hello World"
echo $str | tr 'a-z' 'A-Z'
echo $str | tr 'A-Z' 'a-z'

三、数字与运算

Shell 中数字处理分整数浮点;Bash 对整数有原生支持,浮点常靠 bcawk

整数:推荐 $(( ))

shell
a=10
b=3
echo $((a + b))
echo $((a * b))      # * 在 (( )) 内不必转义
echo $((a / b))      # 整除
echo $((a % b))
# 幂:Bash 4+ 支持 **
echo $((a ** 2))

expr(老用法,易踩坑,仅作了解):

shell
expr $a + $b
expr $a \* $b        # * 要转义

let(赋值与自增):

shell
let a=a*2+3
let a++

浮点:bc / awk

shell
echo "2.5 + 3.8" | bc
echo "scale=2; 10 / 3" | bc

awk -v a=2.5 -v b=3.8 'BEGIN{print a + b}'
awk -v a=10 -v b=3 'BEGIN{printf "%.2f\n", a / b}'

比较

整数[ ] / test 中用:-eq -ne -gt -lt -ge -le

shell
if [ $a -gt $b ]; then
    echo "$a > $b"
fi

浮点需借助工具:

shell
if [ $(echo "$a > $b" | bc) -eq 1 ]; then
    echo "a 大于 b"
fi

示例片段(保留原教学意图)

shell
# 1+...+100
sum=0
for ((i=1; i<=100; i++)); do
    sum=$((sum + i))
done
echo $sum

注意事项

  1. 变量默认可当字符串;参与算术前应确保值为数字。
  2. $((10/3)) 为整数除法;要小数用 bc/awk
  3. expr* 需转义;$(( )) 里不需要。
  4. bcscale 主要影响除法等结果的精度展示。

四、数组

定义与访问

shell
arr=("元素1" "元素2" "元素3")

arr[0]="元素1"
arr+=("元素5")

echo ${arr[0]}
echo ${arr[@]}       # 所有元素
echo ${#arr[@]}      # 元素个数

含空格元素遍历时务必:for x in "${arr[@]}"; do

截取、拼接

shell
echo ${arr[@]:1:3}

arr1=("a" "b")
arr2=("c" "d")
arr3=("${arr1[@]}" "${arr2[@]}")

关联数组(Bash 4+)

shell
declare -A dict
dict["key1"]="value1"
echo ${dict["key1"]}
echo ${!dict[@]}     # 所有键

for key in "${!dict[@]}"; do
    echo "$key: ${dict[$key]}"
done

实用技巧

shell
# 元素是否在数组中(示意)
if [[ " ${arr[@]} " =~ " 元素2 " ]]; then
    echo "存在"
fi

# 字符串按分隔符变数组
str="a,b,c"
IFS=, read -ra arr <<< "$str"

五、与后续章节的衔接