Bash 的模式扩展
最后更新于:2022-04-02 03:53:04
[TOC]
## 模式扩展 概述
1. Bash 是先进行扩展,再执行命令,命令本身并不存在参数扩展,收到什么参数就原样执行。这一点务必需要记住。
2. 模式扩展早于正则表达式出现,它的功能没有正则那么强大灵活,但是优点是简单和方便
## `~` 扩展
用户所在目录
## `?`字符扩展
`?`字符代表文件路径里面的任意单个字符,**除空格**
```
# 存在文件 a.txt、b.txt 和 ab.txt
$ ls ?.txt
a.txt b.txt
$ ls ??.txt
ab.txt
```
## `*`字符扩展
`*`字符代表文件路径里面的任意数量的任意字符,包括零个字符
```
# 存在文件 a.txt、b.txt 和 ab.txt
$ ls *.txt
a.txt b.txt ab.txt
```
输出当前目录的所有文件
```
ls *
```
`*`只匹配当前目录,不会匹配子目录
```
# 子目录有一个 a.txt
# 无效的写法
$ ls *.txt
# 有效的写法
$ ls */*.txt
```
## 方括号扩展 - 匹配中括号中的字符
如果文件不存在,就会原样输出
```
# 存在文件 a.txt 和 b.txt
$ ls [ab].txt
a.txt b.txt
# 只存在文件 a.txt
$ ls [ab].txt
a.txt
```
如果要匹配 `-` 只能放在最前或是最后
```
# 存在 aaa、bbb、aba b-b 三个文件
$ ls ?[-b]
?
bbb aba b-b
```
### `[^...]`和`[!...]` 变体 - 排除括号中的字符
```
# 存在 aaa、bbb、aba 三个文件
$ ls [!a]*
bbb
```
### `[start-end]` 扩展
表示匹配一个连续的范围
`[a-c]`等同于`[abc]`,`[0-9]`匹配`[0123456789]`
```
# 存在文件 report1.txt、report2.txt 和 report3.txt
$ ls report[0-9].txt
report1.txt
report2.txt
report3.txt
```
* `[a-z]`:所有小写字母。
* `[a-zA-Z]`:所有小写字母与大写字母。
* `[a-zA-Z0-9]`:所有小写字母、大写字母与数字。
* `[abc]*`:所有以`a`、`b`、`c`字符之一开头的文件名。
* `program.[co]`:文件`program.c`与文件`program.o`。
* `BACKUP.[0-9][0-9][0-9]`:所有以`BACKUP.`开头,后面是三个数字的文件名。
### 否定形式[!start-end]
```
$ echo report[!1–3].txt
report4.txt report5.txt
```
### 大括号扩展
1. 大括号内部的逗号前后不能有空格
2. 表示分别扩展成大括号里面的所有值
```
$ echo d{a,e,i,u,o}g
dag deg dig dug dog
```
```
$ ls {a,b,c}.txt
ls: 无法访问'a.txt': 没有那个文件或目录
ls: 无法访问'b.txt': 没有那个文件或目录
ls: 无法访问'c.txt': 没有那个文件或目录
```
> 大括号扩展不是文件名扩展。它会扩展成所有给定的值,而不管是否有对应的文件存在
逗号前面可以没有值,表示扩展的第一项为空。
```
$ cp a.log{,.bak}
# 等同于
# cp a.log a.log.bak
```
### 大括号嵌套
```
$ echo {j{p,pe}g,png}
jpg jpeg png
```
### 大括号与中括号区别
```
# 不存在 a.txt 和 b.txt
$ echo [ab].txt
[ab].txt
$ echo {a,b}.txt
a.txt b.txt
```
## {start..end} 扩展 - 大括号的简写新式
```
$ echo d{a..d}g
dag dbg dcg ddg
$ echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5
```
逆序
```
$ echo {5..1}
5 4 3 2 1
```
### 大括号嵌套简写
```
$ echo .{mp{3..4},m4{a,b,p,v}}
.mp3 .mp4 .m4a .m4b .m4p .m4v
```
### {start..end..step} 设置步长
```
$ echo {0..8..2}
0 2 4 6 8
```
### 多个简写形式连用
```
$ echo {a..c}-{1..3}
a-1 a-2 a-3 b-1 b-2 b-3 c-1 c-2 c-3
```
### 实例: 创建目录
新建36个子目录
```
$ mkdir {2007..2009}-{01..12}
drwxr-xr-x. 2 root root 6 Oct 31 14:56 2007-01
drwxr-xr-x. 2 root root 6 Oct 31 14:56 2007-02
...
drwxr-xr-x. 2 root root 6 Oct 31 14:56 2009-11
drwxr-xr-x. 2 root root 6 Oct 31 14:56 2009-12
```
### 实例: 控制 `for`循环次数
```
for i in {1..4}
do
echo $i
done
```
## 子命令扩展 $(commod)
```
$ echo $(date)
Tue Jan 28 00:01:13 CST 2020
//等价于 反引号较老
$ echo `date`
Tue Jan 28 00:01:13 CST 2020
```
## 算术扩展
```
$ echo 2+2
2+2
$ echo $((2 + 2))
4
```
## 量词语法
```
//查看 shopt 是否开启
shopt extglob
//开启
shopt -s extglob
//关闭
shopt -u extglob
```
量词语法用来控制模式匹配的次数
* `?(pattern-list)`:匹配零个或一个模式。
* `*(pattern-list)`:匹配零个或多个模式。
* `+(pattern-list)`:匹配一个或多个模式。
* `@(pattern-list)`:只匹配一个模式。
* `!(pattern-list)`:匹配零个或一个以上的模式,但不匹配单独一个的模式。
```
$ ls abc?(.)txt
abctxt abc.txt
$ ls abc+(.txt|.php)
abc.php abc.txt
```
## shopt
`shopt`命令可以调整 Bash 的行为
```
# 打开某个参数
$ shopt -s [optionname]
# 关闭某个参数
$ shopt -u [optionname]
# 查询某个参数关闭还是打开
$ shopt [optionname]
```
### dotglob 参数 - 扩展结果包括隐藏文件
```
$ shopt -s dotglob
$ ls *
abc.txt .config
```
### nullglob 参数
`nullglob`参数可以让通配符不匹配任何文件名时,返回空字符
```
$ rm b*
rm: 无法删除'b*': 没有那个文件或目录
//开启
$ shopt -s nullglob
$ rm b*
rm: 缺少操作数
```
由于没有`b*`匹配的文件名,所以`rm b*`扩展成了`rm`,导致报错变成了”缺少操作数
### failglob 参数
`failglob`参数使得通配符不匹配任何文件名时,Bash 会直接报错,而不是让各个命令去处理。
```
$ shopt -s failglob
$ rm b*
bash: 无匹配: b*
```
### nocaseglob 参数 - 让通配符扩展不区分大小写
```
$ shopt -s nocaseglob
$ ls /windows/program*
/windows/ProgramData
/windows/Program Files
/windows/Program Files (x86)
```
### globstar 参数 开启 `** `匹配
```
a.txt
sub1/b.txt
sub1/sub2/c.txt
$ shopt -s globstar
$ ls **/*.txt
a.txt sub1/b.txt sub1/sub2/c.txt
```
';