个人理解,模式扩展就是具有特殊意义的占位符
素材,终端请进入samples文件夹,进行测试。
Shell 接收到用户输入的命令以后,会根据空格将用户的输入,拆分成一个个词元(token)。 然后 Shell 会扩展词元里面的特殊字符,扩展完成后才会调用相应的命令。
这种特殊字符的扩展,称为模式扩展(globbing) 其中有些用到通配符,又称为通配符扩展(wildcard expansion)
Bash 一共提供八种扩展:
~
波浪线?
字符*
字符[]
方括号{}
大括号- 变量
- 子命令
- 算术
Bash 先进行扩展,再执行命令。因此扩展的结果是由 Bash 负责,与所要执行的命令无关 命令本身并不存在参数扩展,收到什么参数就原样执行
模式扩展与正则表达式的关系使,模式扩展早于正则表达式出现,功能没有正则那么强大,但是简单、方便
允许用户关闭扩展
set -o noglob
# or
set -f
打开扩展
set +o noglob
# or
set +f
波浪线 ~
会自动扩展成当前用户的主目录
echo ~
~user
表示扩展成用户 user
的主目录
echo ~root
~+
会扩展成当前所在的目录,等同于 pwd
命令。
echo ~+
?
字符代表文件路径里面的任意单个字符,不包括空字符。(注意一点:文件系统中可以使用 ? 做为文件名)。
ls ?.txt
*
字符代表文件路径里面的任意数量的字符串,包括零个字符。
ls *.txt
ls a*.txt
ls *b*
注意,
*
不会匹配隐藏文件(以.
开头的文件),只会匹配当前目录- Bash 4.0 引入一个参数
globstart
,当该参数打开时,允许**
匹配零个或多个子目录
方括号扩展的形式使[...]
,只有文件确实存在的前提才会扩展。
ls [ab].txt
方括号扩展变体:[!...]
和 [^...]
,表示取反。
ls ?[!a]?
方括号扩展有一个简写形式 [start-end]
,表示匹配一个连续的范围。
例如 [a-c]
等同于 [abc]
,[0-9]
匹配 [0123456789]
。
这部分和正则表达式类似。
常用简写例子:
- [a-z] 小写字母
- [A-Z] 大写字母
- [0-9] 数字
大括号扩展 {...}
表示分别扩展成大括号里面的所有值,各个值之间使用逗号分隔。比如 {1,2,3}
扩展成 1 2 3
。(有点数组的意思)。
echo {1,2,3}
echo d{a,e,i,o,u}g
echo Front-{A,B,C}-Back
大括号可以嵌套。
echo {j{p,pe}g,png}
大括号扩展,总是扩展的,和方括号扩展不同。
touch {d,e,f}.txt
注意,
- 大括号内部逗号前后不能有空格,否则大括号扩展失效,会被认为是多个参数。
- 逗号前面可以没值,表示表示该项为空
- 大括号总是先于其他模式进行扩展
大括号扩展有个简写形式,表示扩展成一个连续序列。
比如 {a..z}
扩展成 26 个小写英文。
echo {a..c}
echo d{a..c}g
这个写法的另一个常见用途,是直接用于 for
循环。
for i in {1..4}
do
echo $i
done
这种简写形式还可以使用第二个双点号({start..stop..step}
),用来指定扩展的步长。
echo {0..8..2}
多个简写形式连用,会有循环处理的效果
echo {a..c}{1..3}
Bash 将美元符号 $
开头的词元视为变量,将其扩展成变量值。
echo $SHELL
除了放在 $
后面,也可以放在 ${}
里面
$echo ${SHELL}
$(...)
可以扩展成另一个命令的运行结果,该命令的所有输出都做为返回值。
echo $(date)
# 另一种古老的写法
echo `date`
$(...)
可以嵌套,比如 $(ls $(pwd))
echo $(ls $(pwd))
$((...))
可以扩展成整数运算的结果。
echo $((2 + 2))
[[:class:]]
表示一个字符类,扩展成某一类的特定字符之中。
常见字符类:
[[:alnum:]]
匹配任意英文字母与数字[[:alpha:]]
匹配任意英文字母[[:blank:]]
匹配空格和 Tab 键[[:cntrl:]]
ASCII 码 0-31 的不可打印字符[[:print:]]
ASCII 码 32-127 可打印字符[[:digit:]]
任意数字,0-9[[:graph:]]
A-Z、a-z、0-9 和 标点符号[[:lower:]]
匹配任意小写字母 a-z[[:upper:]]
匹配任意大写字母 A-Z[[:punct:]]
标点符号(除了 A-Z、a-z、0-9 的可打印字符)[[:xdigit:]]
16 进制字符(A-F、a-f 和 0-9)
例子: 打印所有大写字母开头的文件名
echo [[:upper:]]*
字符类的第一个方括号后面,可以加个 !
,表示否定
# 输出所有不以数字开头的文件名
echo [![:digit:]]*
- 通配符是先解释,再执行
- 文件名扩展在不匹配时,会原样输出
- 只适用于单层路径,无法跨目录匹配
- 文件名可以使用通配符
量词语法用来控制模式匹配的次数,它只有在 Bash 的 extglob
参数打开的情况下才能使用,不过一般是默认打开的。
# 查看量词语法开关
shopt extglob
量词语法有下面几种
?(pattern-list)
匹配零个或一个*(pattern-list)
匹配零个或多个+(pattern-list)
匹配一个或多个@(pattern-list)
只匹配一个!(pattern-list)
匹配零个或一个以上的模式,但不匹配单独一个
一些例子
ls abc?(.).xt
调整 Bash 的行为
# 打开某个参数
shopt -s [optionname]
# 关闭某个参数
shopt -u [optionname]
# 查看某个参数状态
shopt [optionname]