Shell变量

Shell 变量详解(新手详细版)

本文档面向零基础新手,从“变量是什么、怎么定义和使用”讲起,详细说明命名、赋值、引用、引号、作用域、环境变量、特殊变量、变量展开等,并配有大量示例。


一、变量是什么?

1.1 一句话理解

变量就是给一段数据(字符串或数字)起个名字,后面用这个名字就能取出或修改这段数据。
Shell 里变量没有类型声明,本质上都是字符串;在算术运算或比较时,Shell 会按需把字符串当数字用。

1.2 典型用途

  • 存一个路径、文件名、配置值;
  • 存命令的返回值或输出(命令替换);
  • 在脚本里多次使用同一值,改一处即可;
  • 和环境变量配合,影响命令行为(如 PATH、HOME)。

二、变量的定义与赋值

2.1 基本语法

变量名=值

注意

  • = 两边不能有空格,否则会被当成“命令 + 参数”。
  • 变量名由字母、数字、下划线组成,不能以数字开头
  • 里若含空格或特殊字符,建议用双引号包起来。
# 正确
name="张三"
count=10
path=/home/user

# 错误:等号两边有空格
# name = "张三"

# 错误:变量名以数字开头
# 1var=1

2.2 值不需要引号的情况

若值里没有空格、#、$、引号等,可以不加引号:

count=0
dir=/tmp

习惯上字符串也加双引号更安全,避免值意外为空或含特殊字符时出错。

2.3 值里有空格或特殊字符

双引号包起来;双引号内 $变量$(命令)被展开

msg="hello world"
path="/home/user/my file.txt"

单引号时,什么都不展开,全部当字面字符:

a='$HOME'
echo $a
# 输出:$HOME(不是家目录路径)

2.4 把命令的输出赋给变量(命令替换)

$(命令)命令(反引号),把命令的标准输出当作字符串赋给变量:

today=$(date +%Y-%m-%d)
echo "今天: $today"

list=$(ls)
# list 里是 ls 的整段输出(多行在一个字符串里)

推荐用 $( ):可嵌套、可读性更好;反引号 ` 在嵌套时容易写错。


三、变量的引用(使用)

3.1 基本引用:$变量名

在命令或字符串里写 $变量名,Shell 会把它替换成变量的值

name="张三"
echo "你好,$name"
# 你好,张三
echo $name
# 张三

3.2 加大括号:${变量名}

${变量名}$变量名 在简单情况下等价;必须${ } 的情况包括:

  • 变量名后面紧跟字母、数字、下划线时,避免被当成另一个变量名:
    a="hello"
    echo "${a}world"
    # helloworld
    echo "$aworld"
    # 空(会找变量 aworld)
  • 变量展开(默认值、截取、替换等)时,都要写成 ${ }

建议:习惯写 ${var},更清晰、少出错。

3.3 引用时加双引号

把变量放在双引号里:“$var”“${var}”,这样即使值为空或含空格,也不会被拆成多个词或触发通配:

file="my file.txt"
cat $file
# 会找 my 和 file.txt 两个文件,报错
cat "$file"
# 正确:一个文件 my file.txt

建议:只要把变量当“一个整体”用,就写 “${var}”


四、只读变量与删除变量

4.1 只读(不可改):readonly 或 declare -r

readonly PI=3.14
# 或
declare -r PI=3.14
PI=3.2
# 报错:只读变量

4.2 删除变量:unset

unset 变量名 会删除该变量,相当于“从未定义过”:

x=1
unset x
echo "${x:-空}"
# 空

注意unset 不能用于只读变量。


五、环境变量与 export

5.1 普通变量只在当前 Shell 里有效

在脚本或交互 Shell 里定义的变量,只在该 Shell 进程内有效;用这个 Shell 去启动子进程(如再运行一个脚本、一条命令)时,子进程默认拿不到这些变量。

5.2 导出为环境变量:export

export 变量名export 变量名=值 会把变量放进环境,之后从当前 Shell 启动的子进程都能看到它:

export MY_VAR="hello"
# 或先赋值再导出
MY_VAR="hello"
export MY_VAR

子脚本里可以直接用 $MY_VAR

5.3 常见环境变量

变量 含义
PATH 可执行文件搜索路径,多个用 : 分隔
HOME 当前用户主目录
USER 当前用户名
SHELL 当前 Shell 路径
PWD 当前工作目录
PS1 主提示符格式

查看所有环境变量:envprintenv;查看某一个:echo $PATH

5.4 一次赋值并导出

export PATH="/opt/bin:$PATH"

这样当前 Shell 和子进程都会用到新的 PATH。


六、特殊变量(Shell 内置)

这些变量由 Shell 自动设置,只读(不能赋值),常用于脚本和函数。

6.1 脚本/命令相关

变量 含义
$0 当前脚本名(或调用的命令名)
$1, $2, … 第 1、2、… 个参数
$# 参数个数
**$*** 所有参数(一个字符串,见下)
$@ 所有参数(多个词,透传用 “$@”

6.2 进程相关

变量 含义
$$ 当前 Shell 的进程 ID(PID)
$! 最后一个后台进程的 PID
$? 上一条命令的退出码(0 表示成功)

示例:

echo "脚本名: $0"
echo "第1个参数: $1"
echo "参数个数: $#"
echo "上一条命令退出码: $?"
echo "当前进程 PID: $$"

6.3 $* 与 $@ 的区别(简要)

  • 不加大引号时,两者行为类似。
  • “$@”:每个参数保持为独立的一个词,适合原样传给其他命令。
  • *“$:所有参数拼成一个字符串**。

脚本里透传参数给子命令时,用 “$@”


七、变量展开(高级用法)

下面都写成 ${变量名…} 形式,用于取默认值、截取、替换等。

7.1 默认值:${var:-默认值}

var 未设置或为空,则展开为“默认值”;不改变 var 的值:

unset x
echo "${x:-没有设置}"
# 没有设置
x=""
echo "${x:-空}"
# 空
x="有值"
echo "${x:-默认}"
# 有值

7.2 赋值型默认值:${var:=默认值}

var 未设置或为空,则先给 var 赋值为“默认值”,再展开为该值;常用于“未设置就设成某值”:

unset y
: ${y:=100}
echo $y
# 100

: 是空命令,只做参数展开,不执行别的;这里用来触发对 y 的赋值。)

7.3 报错退出:${var:?错误信息}

var 未设置或为空,打印“错误信息”到标准错误并退出(非交互 Shell 通常非 0 退出码):

: ${1:?请提供第1个参数}

7.4 有值才替换:${var:+替换值}

var 已设置且非空,展开为“替换值”;否则展开为空:

x=""
echo "结果: ${x:+有}"
# 结果:
x="1"
echo "结果: ${x:+有}"
# 结果: 有

7.5 字符串长度:${#var}

s="hello"
echo ${#s}
# 5

7.6 子串:${var:起始:长度}

从“起始”位置开始取“长度”个字符(起始从 0 开始);省略长度则取到末尾:

s="abcdef"
echo ${s:0:3}
# abc
echo ${s:2:2}
# cd
echo ${s:2}
# cdef

7.7 删除前缀/后缀(模式)

  • ${var#模式}:删掉最短匹配的前缀。
  • ${var##模式}:删掉最长匹配的前缀。
  • ${var%模式}:删掉最短匹配的后缀。
  • ${var%%模式}:删掉最长匹配的后缀。

模式可含 *(通配):

path="/home/user/file.txt"
echo ${path#*/}
# home/user/file.txt
echo ${path##*/}
# file.txt
echo ${path%.*}
# /home/user/file
echo ${path%%.*}
# /home/user/file

7.8 替换:${var/旧/新}、${var//旧/新}

  • ${var/旧/新}:第一个“旧”换成“新”。
  • ${var//旧/新}:所有“旧”换成“新”。
s="hello world"
echo ${s/o/O}
# hellO world
echo ${s//o/O}
# hellO wOrld

7.9 小结表

写法 含义
${var:-default} 空则用 default,不赋值
${var:=default} 空则赋值为 default 并展开
${var:?msg} 空则报错 msg 并退出
${var:+value} 非空则展开 value
${#var} 长度
${var:起:长} 子串
${var#pat} / ${var##pat} 删最短/最长前缀
${var%pat} / ${var%%pat} 删最短/最长后缀
${var/旧/新} / ${var//旧/新} 替换一次/全部

八、引号对变量的影响

8.1 双引号 “…”

  • $变量$(命令)被展开
  • 空格、多数特殊字符保留为字面(除 $、`、 等)。
name="张三"
echo "你好,$name"
# 你好,张三

8.2 单引号 ‘…’

  • 什么都不展开,全部当字面字符;$name 就是四个字符,不是变量值。
echo '$HOME'
# $HOME

8.3 反引号 ...

  • 用于命令替换(和 $( ) 等价);里面的 $变量 会展开。推荐用 $( )

8.4 $’…’(Bash)

  • 支持反斜杠转义,如 n 换行、t 制表符:
echo $'第一行n第二行'

九、变量的作用域(简要)

9.1 默认是“全局”

在脚本顶层定义的变量,在整个脚本(包括其调用的函数)里都可见,除非在函数里用 local

9.2 函数里的 local

local 变量名=值 定义的变量只在当前函数(及它调用的函数)内有效;函数外若有同名变量,不会被修改。

x=1
f() {
  local x=2
  echo "函数内 x=$x"
}
f
echo "函数外 x=$x"
# 函数内 x=2
# 函数外 x=1

9.3 子 Shell 与管道

子 Shell(如 $( )管道右侧)里对变量的赋值不会影响当前 Shell;当前 Shell 的普通变量也不会自动传进子 Shell,除非用 export 变成环境变量。


十、从键盘读入:read

read 从标准输入读一行,拆成多个“词”赋给变量(默认拆成多个变量或一个变量):

read -p "请输入名字: " name
echo "你好,$name"
  • -p “提示”:先输出提示再读。
  • -r:不把 当转义(推荐用)。
  • read -a arr:读一行,按 IFS 拆成数组 arr(Bash)。
read -r line
echo "你输入了: $line"

十一、整数运算与变量

Shell 变量本质是字符串;做算术时用 $(( 表达式 )),表达式里变量可省略 $

a=10
b=3
echo $(( a + b ))
# 13
c=$(( a * b ))
echo $c
# 30

也可用 (( 变量++ ))**、(( 变量 += 1 ))** 等改变变量值(详见 Shell运算符.md)。


十二、实用示例汇总

12.1 使用默认值

name=${1:-"访客"}
echo "你好,$name"

12.2 必填参数检查

: ${1:?用法: $0 <文件名>}
file=$1

12.3 取路径中的文件名或目录

path="/home/user/file.txt"
filename=${path##*/}
dir=${path%/*}

12.4 命令结果赋给变量

count=$(wc -l < file.txt)
today=$(date +%Y-%m-%d)

12.5 环境变量参与路径

echo "$HOME/bin"
export PATH="$HOME/bin:$PATH"

十三、常见坑与建议

  1. 赋值时 = 两边不能有空格x=1 正确,x = 1 会报错。
  2. 引用时尽量加双引号“$var”,避免空或含空格时被拆词。
  3. 能写 ${var} 就写:避免和后面字符连成新变量名。
  4. 子进程要用的变量需 export:否则子脚本、子命令看不到。
  5. 只读变量用 readonly:防止被误改;unset 不能删只读变量。
  6. $? 是上一条命令的退出码:每执行一条命令都会更新,要及时用或存到别的变量。

十四、语法速查表

操作 写法
赋值 var=值var="带空格"
引用 $var${var}
命令替换 var=$(命令)
默认值 ${var:-默认}${var:=默认}
报错退出 ${var:?信息}
长度 ${#var}
子串 ${var:起:长}
删前缀/后缀 ${var#pat}${var%pat}
替换 ${var/旧/新}
只读 readonly vardeclare -r var
导出 export var
删除 unset var
读入 read -r varread -p "提示" var

十五、小结

  • 变量名=值(等号无空格);引用 $var${var};建议加双引号 “${var}”
  • 命令替换$(命令) 把输出当字符串;引号:双引号展开变量,单引号不展开。
  • 环境变量export 后子进程可见;只读readonly删除unset
  • 特殊变量$0、$1、$#、$@、$?、$$ 等;透传参数用 “$@”
  • 变量展开${var:-default}${#var}${var:起:长}${var#pat}${var/旧/新} 等。

多写几段脚本练赋值、引用、默认值、命令替换、export、read,再结合 Shell传递参数.mdShell运算符.mdShell数组.md 一起用,变量就能用熟。


文档以 Bash 为准;sh 或其它 Shell 在部分展开、read、export 等上可能略有差异。

发表评论