概要
本文系统性地总结了 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 中的特殊语法、变量、展开与控制结构。
理解这些机制后,可编写更安全、高复用的自动化脚本,实现复杂的系统任务控制。
