通配符与扩展

通配符用于匹配文件名,是 Shell 最常用的功能之一。与正则表达式不同,通配符由 Shell 解释,用于文件名扩展。Bash 还提供了花括号扩展、波浪号扩展等高级功能。

基本通配符

* 匹配任意字符

* 匹配 0 个或多个任意字符:

ls *.txt
rm *.log
cp *.jpg /backup/

? 匹配单个字符

? 匹配恰好一个任意字符:

ls file?.txt
ls ???.txt

匹配 file1.txt、file2.txt,不匹配 file10.txt。

[] 字符集合

[] 匹配方括号中的任意一个字符:

ls file[123].txt
ls file[1-3].txt
ls [abc]*
ls [!0-9]*  # 排除数字开头

[!...][^...] 表示排除。

字符类

ls [[:alpha:]]*
ls [[:digit:]]*
ls [[:upper:]]*

花括号扩展

花括号扩展生成多个字符串,不依赖文件是否存在。

枚举

echo {a,b,c}
echo file{1,2,3}.txt
mkdir dir{A,B,C}

输出:

a b c
file1.txt file2.txt file3.txt

范围

echo {1..10}
echo {a..z}
echo {A..Z}
mkdir dir{1..10}

步长

echo {0..10..2}
echo {a..z..3}

输出:

0 2 4 6 8 10
a d g j m p s v y

嵌套

echo {a,b}{1,2,3}
echo /usr/{local/,}bin

输出:

a1 a2 a3 b1 b2 b3
/usr/local/bin /usr/bin

实用示例

mkdir -p project/{src,doc,test}
cp file.{txt,bak}
mv style.{css,scss} backup/
for i in {1..10}; do echo $i; done

波浪号扩展

用户目录

echo ~
echo ~/Documents
echo ~root

~ 是当前用户的家目录,~user 是指定用户的家目录。

工作目录

echo ~+
echo ~-

~+ 是当前工作目录,~- 是上一个工作目录。

路径扩展顺序

Shell 按以下顺序处理扩展:

  1. 花括号扩展
  2. 波浪号扩展
  3. 参数和变量扩展
  4. 命令替换
  5. 算术扩展
  6. 进程替换
  7. 文件名扩展(通配符)
echo ~/{a,b}*.txt

先扩展 ~,再扩展 {a,b},最后匹配 *.txt

禁用扩展

单引号

单引号内的所有字符原样保留:

echo '*.txt'
echo '{a,b,c}'
echo '$HOME'

转义

反斜杠转义单个字符:

echo \*.txt
echo \$HOME

set -f

set -f 禁用文件名扩展:

set -f
echo *
set +f

扩展通配符

Bash 支持 ksh 风格的扩展通配符,需要启用 extglob

shopt -s extglob
模式含义
?(pattern)匹配 0 次或 1 次
*(pattern)匹配 0 次或多次
+(pattern)匹配 1 次或多次
@(pattern)匹配恰好 1 次
!(pattern)匹配不包含 pattern
ls *.?(txt|md)
ls *.+(jpg|png)
ls !(backup)
rm !(important).txt

大小写不敏感匹配

shopt -s nocaseglob
ls *.TXT

启用后 *.txt 也能匹配 .TXT

隐藏文件

默认 * 不匹配以 . 开头的隐藏文件:

ls *
ls .*
ls * .*

.* 匹配隐藏文件,但也会匹配 ...

更安全的方式:

ls .[!.]*
ls .[!.]* .??*

实用示例

批量重命名

for f in *.txt; do
    mv "$f" "${f%.txt}.md"
done

批量创建目录

mkdir -p project/{src/{main,test},doc,config}

备份文件

cp file.txt{,.bak}

批量处理

for f in image{001..100}.jpg; do
    convert "$f" "${f%.jpg}_thumb.jpg"
done

小结

  • * 匹配任意字符,? 匹配单个字符,[] 字符集合
  • 花括号扩展生成多个字符串,{a,b}{1..10}
  • ~ 扩展为用户目录
  • 单引号禁用所有扩展
  • shopt -s extglob 启用扩展通配符
  • 通配符由 Shell 解释,与正则表达式不同