Bash特殊语法、特殊变量与特殊展开完全指南

概要

本文系统性地总结了 Bash Shell 中使用的所有特殊语法、特殊变量、展开规则与控制结构。
通过本指南,你可以完全掌握 Bash 的动态行为与脚本结构控制。


关于变量表示

动态或依赖环境的值以 <<变量名>> 表示,并附有具体示例。

变量名 示例 说明
<<var>> name, path, user 任意变量名
<<default>> guest, 8080 默认值或替代值
<<pattern>> *.txt, */ 文件名或字符串模式
<<offset>> 0, 3 子字符串起始位置(从0开始)
<<length>> 4, 10 子字符串长度
<<prefix>> ENV_, HOST 变量名前缀匹配
<<index>> 0, 1, 2 数组或关联数组索引(键)
<<file>> /tmp/test.txt 文件路径

Step 1: 特殊符号(元字符)

符号 含义 示例
* 匹配任意字符串 ls *.txt
? 匹配任意单个字符 ls ?.sh
[a-z] 范围匹配 ls [A-Z]*
{a,b} 大括号展开 mv {hoge,huga}
{1..3} 数值序列展开 touch file{1..3}.txt
$ 变量展开 echo $HOME
!(逻辑否定) 条件取反 [[ ! -f test.txt ]]
!(历史展开) 执行命令历史 !10
~ 主目录展开 cd ~
; 命令连接 pwd; ls
&& 前一命令成功时执行 make && echo OK
` `
& 后台执行 sleep 5 &
` ` 管道
> 输出重定向 echo hi > out.txt
>> 追加输出 echo hi >> out.txt
< 输入重定向 wc -l < file.txt
() 子Shell执行 (cd /tmp; ls)
{} 当前Shell执行 { echo A; echo B; }
\ 转义 echo \$HOME
' ' 不展开的字面量 echo '$USER'
" " 展开字符串 echo "$USER"

Step 2: 特殊变量

变量 含义 示例
$0 脚本名 echo $0
$1~$9 脚本参数 echo $1
$@ 参数数组 for a in "$@"; do echo $a; done
$# 参数数量 echo $#
$? 上一命令的返回码 ls /nope; echo $?
$$ 当前进程ID echo $$
$! 最近后台任务PID sleep 10 & echo $!
$- 当前Shell选项 echo $-
$_ 上一命令的最后一个参数 echo $_
$PPID 父进程ID echo $PPID
$RANDOM 随机数(0–32767) echo $RANDOM
$SECONDS Shell启动到现在的秒数 echo $SECONDS
$FUNCNAME 函数名 myf(){ echo $FUNCNAME; }; myf
$PIPESTATUS[@] 管道中各命令返回码 `ls

Step 3: 参数展开(Parameter Expansion)

语法 含义 示例
${<<var>>} 展开变量 name=user; echo ${name}
${<<var>>:-<<default>>} 未定义则使用默认值 echo ${user:-guest}
${<<var>>:=<<default>>} 未定义则赋默认值 echo ${port:=8080}
${<<var>>:+alt} 定义则使用alt x=1; echo ${x:+OK}
${<<var>>:?msg} 未定义时报错 echo ${config:?missing}
${#<<var>>} 字符串长度 echo ${#name}
${<<var>>%<<pattern>>} 删除末尾最短匹配 path=/a/b/c; echo ${path%/*}
${<<var>>%%<<pattern>>} 删除末尾最长匹配 echo ${path%%/*}
${<<var>>#<<pattern>>} 删除开头最短匹配 echo ${path#*/}
${<<var>>##<<pattern>>} 删除开头最长匹配 echo ${path##*/}
${<<var>>/<<pattern>>/<<repl>>} 替换首次匹配 echo ${msg/foo/bar}
${<<var>>//<<pattern>>/<<repl>>} 替换所有匹配 echo ${msg// /_}
${<<var>>:<<offset>>} 截取字符串 s=abcdef; echo ${s:2}
${<<var>>:<<offset>>:<<length>>} 截取指定长度 echo ${s:1:3}
${!<<prefix>>*} 列出指定前缀变量 HOST1=x; echo ${!HOST*}
${!<<var>>} 间接引用 ref=NAME; NAME=user; echo ${!ref}
${<<var>>,} / ${<<var>>^^} 大小写转换 n=abc; echo ${n^^}
${<<var>>@Q} 带引号展开 x='abc'; echo ${x@Q}

Step 4: 数组与关联数组

# 普通数组
arr=(a b c)
echo ${arr[<<index>>]}
echo ${#arr[@]}
for i in "${arr[@]}"; do echo $i; done

# 关联数组
declare -A map
map[<<index>>]=100
map[name]=user
echo ${map[<<index>>]}
echo ${!map[@]}

Step 5: 算术展开

x=5
y=3
echo $((x + y))
((x *= 2))
echo $x

Step 6: 条件判断与比较

# 字符串
if [ "$USER" = "root" ]; then echo root; fi

# 数值
if [ "$x" -lt 10 ]; then echo small; fi

# 文件
if [ -f /etc/passwd ]; then echo exists; fi

# 正则匹配
s="hello123"
[[ $s =~ [0-9]+ ]] && echo matched

Step 7: 命令替换与子Shell

echo "Today: $(date +%Y-%m-%d)"
(cd /tmp; ls)

Step 8: 重定向与文件描述符

echo "Hello" > <<file>>
echo "Append" >> <<file>>
wc -l < <<file>>
ls /nope 2> err.log
echo "Error" >&2
exec 3> custom.log
echo "via fd3" >&3
exec 3>&-

文件描述符说明(FD)

FD号 名称 说明 示例
0 标准输入 从键盘或文件读取 < file.txt
1 标准输出 输出到终端或文件 echo test > out.txt
2 标准错误输出 输出错误 ls /nope 2> err.log
3+ 自定义FD 用户自定义输出流 exec 3> log.txt

示例:

exec 3> process.log
echo "执行开始" >&3
exec 3>&-

Step 9: Trap与错误处理

set -e
set -u
set -x
set -o pipefail

trap 'echo 已结束' EXIT
trap 'echo 错误发生' ERR

Step 10: 作业控制

sleep 10 &
jobs
fg %1
bg %1
disown %1
kill %1

%1 的含义

后台运行命令会生成“作业”。
jobs 可显示当前作业编号:

sleep 60 &
jobs

输出:

[1]+ Running sleep 60 &
符号 含义
%1 指代作业1
%+ 当前作业
%- 上一个作业

Step 11: 特殊命令与保留字

:            # 空命令,始终成功
true         # 返回成功
false        # 返回失败
source ~/.bashrc
eval "echo run"
{ echo A; echo B; }

总结

本文完整整理了 Bash 中的特殊语法、变量、展开与控制结构。
理解这些机制后,可编写更安全、高复用的自动化脚本,实现复杂的系统任务控制。