glob 模式介绍

glob 模式介绍

[TOC]

本文介绍 shell 中的 glob 模式, 一种简化的正则表达式规则, 常用于匹配各种路径.

glob 模式 最初是贝尔实验室 Unix V6 系统上的一个 /etc/glob 的命令(全称: globbing pathnames. 详见 man 文档), 用于展开命令行中的通配符. 成为 shell 内建的命令. 系统也提供了该功能的 C 语言库函数glob()(名为 glob(3)).

基础语法

相比正则表达式大量的元字符, glob 模式中元字符极少, 所以掌握起来也很快. glob 默认不匹配隐藏文件(以点.开头的文件或目录), 下面是 glob 的语法:

通配符 描述 示例 匹配 不匹配
* 匹配0个或多个字符, 包含空串 Law* Law, LawsLawer La, aw
? 匹配1个字符 ?at cat, bat at
[abc] 匹配括号内字符集合中的单个字符 [][!]at !at [at], at, at!
[a-z] 匹配括号内字符范围中的单个字符 [a-z]at aat, bat, zat at, bcat, Bat
[^abc][!abc] 匹配非括号内字符集合中的单个字符
注意 ^ 是不符合 POSIX 标准的.
[!CB]at cat, bat Cat, Bat
[^a-z][!a-z] 匹配非括号内字符范围中的单个字符
注意 ^ 是不符合 POSIX 标准的.
[!A-Z]at aat, bat, zat Aat, Bat, Zat

一些注意项:

转义: 放在 "" 或者 '' 中间的 * 会被转义成只匹配 * 字符本身, 失去其通配符的特性. 例如: cp -r ${PATH}"/a/*" . 找到的目录只会去匹配名为 * 的目录. 如果想要实线其通配符效果, 不能对其转义, 例如: cp -r ${PATH}"/a/"* . 除了 '' 以及 "" 还可以使用 \ 进行转义.

在 bash 命令行中[!abc]需要转义成[\!abc].

这些通配符不能被 () 包裹. 否则失去通配符的意义.

[]- range 规则是基于 ASCII 码的(一般而言, 有些平台也许有自己的序列定义, 可以通过 LC_COLLATE 变量用 locale 命令查看), 换句话说, 只要是在 ASCII 码内的连续序列都可以成为匹配 range. 例如 [--0] 匹配 -, ., 0, ASCII 码中的序列如下表, 但是 / 转义符是个例外不在其列.

二进制 十进制 十六进制 ASCII 字符/缩写
00101101 45 2D -
00101110 46 2E .
00101111 47 2F /
00110000 48 30 0

如上面的 range 匹配语法. 目录的 / 无法被 *, ?, [.-0] 匹配, 必须显式地写出 / 进行匹配.

注意 . 开头的文件无法被 *, ?, 匹配, 例如 rm * 不会去删除 .profile 文件. 如果想删除所有的隐藏文件可以使用命令 rm .*, 此命令不会去删除 . .. 两个隐藏目录, 即便是加上 -r 参数也不行, 如果也想删除这两个文件只能删除整个目录.

与正则表达式 regexp 的差异

glob 模式主要用于匹配文件路径, 当然也可以用于匹配字符串, 不过在匹配字符串的能力上比 regexp 要弱很多. 因此 glob 模式通常用来匹配目录以及文件, 而不是文本. 由于 glob 模式和 regexp 存在相同的元字符, 但是含义却不同, 容易导致混淆, 为了避免混淆, 下面将 glob 模式转换成对应的 regexp 表示, 以便区分他们的异同点.

glob regexp 精确的 regexp
* .* ^(?!\.)[^\/]*?$
? . ^(?!\.)[^\/]$
[a-z] [a-z] ^[a-z]$

glob 匹配的是整个字符串, 而 regexp 默认匹配的是子串, regexp 如果要匹配整个字符串需显式指定^$. 正则表达式中的(?!\.), 其表示不匹配隐藏文件

扩展语法

除了基础语法外, bash 还支持 glob 的一些扩展语法, 主要包含三种:

  • Brace Expansion
  • globstar
  • extglob

三种扩展语法的定义和描述如下:

通配符 描述 示例 匹配 不匹配
{x, y, ...} Brace Expansion, 展开花括号内容, 支持展开嵌套括号 a.{png,jp{,e}g} a.png, a.jpg, a.jpeg
** globstar, 匹配所有文件和任意层目录, 如果**后面紧接着/则只匹配目录, 不含隐藏目录 src/** src/a.js, src/b/a.js, src/b/ src/.hide/a.js
?(pattern-list) 匹配0次或1次给定的模式 a.?(txt|bin) a., a.txt, a.bin a
*(pattern-list) 匹配0次或多次给定的模式 a.*(txt|bin) a., a.txt, a.bin, a.txtbin a
+(pattern-list) 匹配1次或多次给定的模式 a.+(txt|bin) a.txt, a.bin, a.txtbin a., a
@(pattern-list) 匹配给定的模式 a.@(txt|bin) a.txt, a.bin a., a.txtbin
!(pattern-list) 匹配非给定的模式 a.!(txt|bin) a., a.txtbin a.txt, a.bin

pattern-list 是一组以|作为分隔符的模式集合, 例如abc|a?c|ac*

注意: 在使用花括号 {} 的时候, 里面的单个字符串需要使用单引号或者双引号括住, 否则就会视为多个的单个字符. 同时, 它适用于多个匹配, 如果硬要进行单个匹配必须显式指明其他的为空, 例如, ls :{"src",}, , 后为空, 只匹配 src 一个目录.

在使用通配符的过程中可能会遇到文件名中包含了特殊字符的情况. 可以使用专用字符集(下面介绍)匹配, 也可以使用转义或者使用引号来匹配(可以少打一些字符).

例如文件 a␣.sh(符号表示空格)的匹配:

1
2
3
$ cat *[[:space:]].sh #专用字符集匹配
$ cat *\ .sh #转义匹配, 注意 \ 后有空格
$ cat *" ".sh #引号匹配, 注意 "" 中间有空格

专用字符集

字符 意义
[:alnum:] 任意数字或者字母
[:alpha:] 任意字母
[:space:] 空格
[:lower:] 小写字母, 等效于 [a-z]
[:digit:] 任意数字
[:upper:] 任意大写字母
[:cntrl:] 控制符
[:graph:] 图形
[:print:] 可打印字符
[:punct:] 标点符号
[:xdigit:] 十六进制数
[:blank:] 空白字符(未验证)

注意: 在使用专属字符集的时候, 字符集之外还需要用 [ ] 来包含住, 否则专用字符集不会生效, 例如 [[:space:]].

使用专用字符集的意义, 例如与其使用 [a-z]而是使用 [:lower:], 是因为一些语言中小写字母不仅仅只包含英语的小写字母, 例如德语系里面的 ä.

需要转义的 Linux shell 元字符

字符 作用
IFS 由 < space > 或 < tab > 或 < enter > 三者之一组成
CR 由 < enter > 产生
= 设定变量
$ 作变量或运算替换
> 重导向标准输出
< 重导向标准输入
| 命令管线
& 重导向文件描述符, 或将命令静默执行
( ) 将其内的命令置于 nested subshell 执行, 或用于运算或命令替换
{ } 将其内的命令置于 non-named function 中执行, 或用在变量替换的界定范围
; 在前一个命令结束时, 而忽略其返回值, 继续执行下一个命令
&& 在前一个命令结束时, 若返回值为 true, 继续执行下一个命令
|| 在前一个命令结束时, 若返回值为 false, 继续执行下一个命令
! 执行 history 中的命令

Collating symbols and equivalence classes–不常用

用来匹配一些语言中的字符.

字符 例子 作用
[. .] [.ch.] a collating element defined for the current locale.
[= =] [[=a=]] [aáaäâ]

参考链接:

https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching

https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html#Brace-Expansion

glob(7) — Linux manual page

https://juejin.cn/post/6844904077801816077

https://www.cnblogs.com/divent/p/5762154.html

作者

cx

发布于

2022-06-20

更新于

2022-07-19

许可协议