变量

变量是脚本的基本组成单位。Shell 的变量机制简单灵活,但也有容易踩坑的地方。

变量定义

Shell 定义变量很简单,不需要声明类型:

NAME="张三"
AGE=25
PATH="/usr/local/bin"

注意几点:

  • 等号两边不能有空格
  • 变量名区分大小写
  • 变量名只能包含字母、数字、下划线,且不能以数字开头
# 错误写法
NAME = "张三"      # 等号两边有空格
1VAR="test"        # 以数字开头

# 正确写法
NAME="张三"
_VAR="test"

变量使用

使用变量要加 $ 符号:

NAME="张三"
echo $NAME
echo ${NAME}    # 推荐用花括号,更清晰

花括号在变量拼接时特别有用:

APP="myapp"
echo $APP_server    # 变量名是 APP_server,不是 APP
echo ${APP}_server  # 变量名是 APP,输出 myapp_server

只读变量

readonly 声明只读变量:

PI=3.14
readonly PI

PI=3.14159  # 报错:PI: readonly variable

删除变量

unset 删除变量:

NAME="张三"
unset NAME
echo $NAME   # 输出空

注意 unset 不能删除只读变量。

变量类型

Shell 变量按作用域分三类:

局部变量

只在当前脚本或函数内有效:

#!/bin/bash
NAME="张三"   # 局部变量
echo $NAME

环境变量

对子进程也有效,用 export 导出:

export JAVA_HOME=/usr/lib/jvm/java-11
./child_script.sh   # 子脚本能访问 JAVA_HOME

常见的系统环境变量:

echo $HOME      # 用户主目录
echo $PATH      # 命令搜索路径
echo $USER      # 当前用户
echo $PWD       # 当前目录
echo $SHELL     # 当前 Shell

特殊变量

Shell 预定义的特殊变量:

$0    # 脚本名称
$1-$9 # 第1到第9个参数
$#    # 参数个数
$@    # 所有参数(作为独立字符串)
$*    # 所有参数(作为单个字符串)
$?    # 上一个命令的退出码
$$    # 当前进程 PID
$!    # 后台运行的最后一个进程 PID

示例:

#!/bin/bash
echo "脚本名: $0"
echo "第一个参数: $1"
echo "参数个数: $#"
echo "所有参数: $@"

# 运行
./test.sh a b c
# 脚本名: ./test.sh
# 第一个参数: a
# 参数个数: 3
# 所有参数: a b c

变量默认值

变量可能为空,设置默认值避免出错:

# 如果 VAR 为空,使用默认值
echo ${VAR:-default}

# 如果 VAR 为空,赋值并使用
echo ${VAR:=default}

# 如果 VAR 为空,报错退出
echo ${VAR:?错误:变量未设置}

# 如果 VAR 非空,使用替代值
echo ${VAR:+替代值}

实际应用:

#!/bin/bash
# 备份脚本,可指定备份目录

BACKUP_DIR=${1:-/backup}  # 第一个参数或默认 /backup
echo "备份目录: $BACK_DIR"

变量作用域

函数内的变量默认是全局的:

#!/bin/bash

test_func() {
    VAR="hello"   # 这也是全局变量
}

test_func
echo $VAR   # 输出 hello

local 声明局部变量:

#!/bin/bash

test_func() {
    local VAR="hello"   # 局部变量
    echo "函数内: $VAR"
}

test_func
echo "函数外: $VAR"   # 输出空

从命令读取变量

# 方式一:反引号(旧写法)
DATE=`date +%Y%m%d`

# 方式二:$()(推荐)
DATE=$(date +%Y%m%d)
USER_NAME=$(whoami)

读取用户输入

#!/bin/bash
echo -n "请输入名字: "
read NAME
echo "你好, $NAME"

# 简化写法
read -p "请输入名字: " NAME
echo "你好, $NAME"

小结

变量使用要点:

  1. 定义时等号两边不能有空格
  2. 使用时加 $,推荐用 ${}
  3. 区分局部变量、环境变量、特殊变量
  4. 善用默认值避免空变量错误
  5. 函数内用 local 声明局部变量