Skip to content

Commit afec8fe

Browse files
committed
docs: edit expansion
1 parent 015dc7c commit afec8fe

File tree

3 files changed

+73
-36
lines changed

3 files changed

+73
-36
lines changed

chapters.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
- intro.md: Bash 简介
22
- grammar.md: Bash 的基本语法
3+
- expansion.md: Bash 的模式扩展
34
- quotation.md: 引号和转义
45
- string.md: 字符串操作
5-
- expansion.md: Bash 的模式扩展
66
- arithmetic.md: Bash 的算术运算
77
- variable.md: Bash 变量
88
- script.md: Bash 脚本简介

docs/expansion.md

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,22 @@ Shell 接收到用户输入的命令以后,会根据空格将用户的输入
66

77
这种特殊字符的扩展,称为通配符扩展(wildcard expansion)或者模式扩展(globbing)。Bash 一共提供八种扩展,先进行扩展,然后再执行命令。
88

9-
早期的 Unix 系统有一个`/etc/glob`文件,保存扩展的模板。后来 Bash 内置了这个功能,但是这个名字保留了下来。特殊字符的扩展早于正则表达式出现,可以看作是原始的正则表达式。它的功能没有正则那么强大灵活,但是优点是简单和方便。
9+
- 波浪线扩展
10+
- `?` 字符扩展
11+
- `*` 字符扩展
12+
- 方括号扩展
13+
- 大括号扩展
14+
- 变量扩展
15+
- 子命令扩展
16+
- 算术扩展
17+
18+
本章介绍这八种扩展。
19+
20+
Bash 是先进行扩展,再执行命令。因此,扩展的结果与所要执行的命令无关,是由 Bash 负责的。命令本身并不存在参数扩展,收到什么参数就原样执行。这一点务必需要记住。
21+
22+
`globbing`这个词,来自于早期的 Unix 系统有一个`/etc/glob`文件,保存扩展的模板。后来 Bash 内置了这个功能,但是这个名字就保留了下来。
23+
24+
模式扩展与正则表达式的关系是,模式扩展早于正则表达式出现,可以看作是原始的正则表达式。它的功能没有正则那么强大灵活,但是优点是简单和方便。
1025

1126
Bash 允许用户关闭通配符扩展。
1227

@@ -33,14 +48,14 @@ $ echo ~
3348
/home/me
3449
```
3550

36-
如果要进入主目录的某个子目录,通常会把子目录放在波浪号后面
51+
`~/dir`表示扩展成主目录的某个子目录,`dir`是主目录里面的一个子目录名
3752

3853
```bash
3954
# 进入 /home/me/foo 目录
4055
$ cd ~/foo
4156
```
4257

43-
如果`~`后面是已经存在的用户名,则会返回该用户的主目录
58+
`~user`表示扩展成用户`user`的主目录
4459

4560
```bash
4661
$ echo ~foo
@@ -52,14 +67,14 @@ $ echo ~root
5267

5368
上面例子中,Bash 会根据波浪号后面的用户名,返回该用户的主目录。
5469

55-
如果是不存在的用户名,则波浪号扩展不起作用。
70+
如果`~user``user`是不存在的用户名,则波浪号扩展不起作用。
5671

5772
```bash
5873
$ echo ~nonExistedUser
5974
~nonExistedUser
6075
```
6176

62-
此外,`~+`会返回当前所在的目录,等同于`pwd`命令。
77+
`~+`会扩展成当前所在的目录,等同于`pwd`命令。
6378

6479
```bash
6580
$ cd ~/foo
@@ -69,7 +84,7 @@ $ echo ~+
6984

7085
## `?` 字符扩展
7186

72-
`?`字符代表文件路径里面的任意单个字符,不包括空字符。比如,`Data???`匹配所有`Data`开头后面跟着三个字符的文件名
87+
`?`字符代表文件路径里面的任意单个字符,不包括空字符。比如,`Data???`匹配所有`Data`后面跟着三个字符的文件名
7388

7489
```bash
7590
# 存在文件 a.txt 和 b.txt
@@ -89,7 +104,7 @@ ab.txt
89104

90105
上面命令中,`??`匹配了两个字符。
91106

92-
注意,Bash 是先进行扩展,再执行命令。因此,扩展的结果决定了命令执行的结果,各种扩展只是 Bash 的功能,命令本身并不存在参数扩展,收到什么参数就原样执行
107+
`?` 字符扩展属于文件名扩展,只有文件确实存在的前提下,才会发生扩展。如果文件不存在,扩展就不会发生
93108

94109
```bash
95110
# 当前目录有 a.txt 文件
@@ -105,7 +120,7 @@ $ echo ?.txt
105120

106121
## `*` 字符扩展
107122

108-
`*`字符代表文件路径里面的任意数量字符,包括零个字符。
123+
`*`字符代表文件路径里面的任意数量的字符,包括零个字符。
109124

110125
```bash
111126
# 存在文件 a.txt、b.txt 和 ab.txt
@@ -133,11 +148,22 @@ b.txt ab.txt
133148
# 显示所有隐藏文件
134149
$ echo .*
135150

151+
# 与方括号扩展结合使用,
136152
# 只显示正常的隐藏文件,不显示 . 和 .. 这两个特殊文件
137153
$ echo .[!.]*
138154
```
139155

140-
## 方括号模式
156+
`*`字符扩展也属于文件名扩展,只有文件确实存在的前提下才会扩展。如果文件不存在,就会原样输出。
157+
158+
```bash
159+
# 当前目录不存在 c 开头的文件
160+
$ echo c*.txt
161+
c*.txt
162+
```
163+
164+
上面例子中,当前目录里面没有`c`开头的文件,导致`c*.txt`会原样输出。
165+
166+
## 方括号扩展
141167

142168
方括号模式是`[...]`,可以匹配方括号之中的任意一个字符,比如`[aeiou]`可以匹配五个元音字母中的任意一个。该模式属于文件名匹配,即匹配后的结果必须符合现有的文件路径,如果不存在匹配,就会保持原样,不进行扩展。
143169

@@ -168,7 +194,7 @@ aba bbb
168194

169195
注意,如果需要匹配`[`字符,可以放在方括号内,比如`[[aeiou]`。如果需要匹配连字号`-`,只能放在方括号内部的开头或结尾,比如`[-aeiou]``[aeiou-]`
170196

171-
## [start-end] 模式
197+
## [start-end] 扩展
172198

173199
方括号模式`[start-end]`可以表示一个连续的范围。
174200

docs/quotation.md

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ $ echo -e "a\tb"
5050
a b
5151
```
5252

53+
上面例子中,命令行直接输出不可打印字符,Bash 不能正确解释。必须把它们放在引号之中,然后使用`echo`命令的`-e`参数。
54+
5355
由于反斜杠可以对换行符转义,使得 Bash 认为换行符是一个普通字符,从而可以将一行命令写成多行。
5456

5557
```bash
@@ -61,11 +63,13 @@ $ mv \
6163
$ mv /path/to/foo /path/to/bar
6264
```
6365

64-
上面例子中,如果一条命令过长,就可以在行尾使用反斜杠,将其改写成多行。
66+
上面例子中,如果一条命令过长,就可以在行尾使用反斜杠,将其改写成多行。这是常见的多行命令的写法。
6567

6668
## 单引号
6769

68-
单引号用于保留字符的字面含义,各种特殊字符都能在单引号里面变为普通字符,包括星号(`*`)、美元符号(`$`)、反斜杠(`\`)等。也就是说,单引号之中所有字符都会变成普通字符。
70+
Bash 允许字符串放在单引号或双引号之中,加以引用。
71+
72+
单引号用于保留字符的字面含义,各种特殊字符在单引号里面,都会变为普通字符,比如星号(`*`)、美元符号(`$`)、反斜杠(`\`)等。
6973

7074
```bash
7175
$ echo '*'
@@ -81,9 +85,9 @@ $ echo '$(echo foo)'
8185
$(echo foo)
8286
```
8387

84-
上面命令中,单引号使得 Bash 扩展、变量引用、算术运算和子命令,都失效了。
88+
上面命令中,单引号使得 Bash 扩展、变量引用、算术运算和子命令,都失效了。如果不使用单引号,它们都会被 Bash 自动扩展。
8589

86-
由于反斜杠在单引号里面会变成普通字符,所以如果单引号之中,还要使用单引号,不能使用转义,需要在外层的单引号前面加上一个美元符号(`$`),然后再对里层的单引号转义。
90+
由于反斜杠在单引号里面变成了普通字符,所以如果单引号之中,还要使用单引号,不能使用转义,需要在外层的单引号前面加上一个美元符号(`$`),然后再对里层的单引号转义。
8791

8892
```bash
8993
# 不正确
@@ -105,14 +109,14 @@ it's
105109
106110
## 双引号
107111
108-
双引号可以保留大部分特殊字符的本来含义(比如`*`),但是三个符号除外:美元符号`$`、反引号和反斜杠(`\`)。
112+
双引号比单引号宽松,可以保留大部分特殊字符的本来含义,但是三个字符除外:美元符号`$`、反引号和反斜杠(`\`。也就是说,这三个字符在双引号之中,会被 Bash 自动扩展
109113
110114
```bash
111115
$ echo "*"
112116
*
113117
```
114118
115-
上面例子中,通配符`*`放在双引号之中,就变成了普通字符,会原样输出。
119+
上面例子中,通配符`*`放在双引号之中,就变成了普通字符,会原样输出。这一点需要特别留意,双引号里面不会进行文件名扩展。
116120
117121
```bash
118122
$ echo "$SHELL"
@@ -132,7 +136,7 @@ $ echo "\\"
132136
\
133137
```
134138
135-
上面例子中,反斜杠在双引号之中保持特殊含义,用来转义。可以使用反斜杠,在双引号之中插入双引号,以及插入反斜杠本身
139+
上面例子中,反斜杠在双引号之中保持特殊含义,用来转义。所以,可以使用反斜杠,在双引号之中插入双引号,或者插入反斜杠本身
136140
137141
由于双引号将换行符解释为普通字符,所以可以利用双引号,在命令行输入多行文本。
138142
@@ -145,23 +149,14 @@ world
145149
146150
上面命令中,Bash 正常情况下会将换行符解释为命令结束,但是换行符在双引号之中就是普通字符,所以可以输入多行。`echo`命令会将换行符原样输出,显示的时候正常解释为换行。
147151
148-
如果文件名包含空格,就可以把它放在双引号之中
152+
双引号的另一个常见的使用场合是,文件名包含空格。这时就必须使用双引号,将文件名放在里面
149153
150154
```bash
151155
$ ls "two words.txt"
152156
```
153157
154158
上面命令中,`two words.txt`是一个包含空格的文件名,否则就会被 Bash 当作两个文件。
155159
156-
注意,双引号之中,不会进行文件名扩展。
157-
158-
```bash
159-
$ echo "*"
160-
*
161-
```
162-
163-
上面例子中,双引号之中的星号不会扩展成文件名。
164-
165160
双引号会原样保存多余的空格。
166161
167162
```bash
@@ -187,7 +182,7 @@ $ echo "$(cal)"
187182
26 27 28 29 30 31
188183
```
189184
190-
上面命令中,如果`$(cal)`不放在双引号之中,`echo`就会将所有结果以单行输出,丢弃了所有原始的格式。
185+
上面例子中,如果`$(cal)`不放在双引号之中,`echo`就会将所有结果以单行输出,丢弃了所有原始的格式。
191186
192187
## Here 文档
193188
@@ -253,7 +248,21 @@ $foo
253248
254249
上面例子中,Here 文档的开始标记(`_example_`)放在单引号之中,导致变量替换失效了。
255250
256-
Here 文档的本质是重定向,它将字符串重定向输出给某个命令,相当于包含了`echo`命令。所以,Here 字符串只适合那些可以接受标准输入作为参数的命令,对于其他命令无效,比如`echo`命令就不能用 Here 文档。
251+
Here 文档的本质是重定向,它将字符串重定向输出给某个命令,相当于包含了`echo`命令。
252+
253+
```bash
254+
$ command << token
255+
string
256+
token
257+
258+
# 等同于
259+
260+
$ echo string | command
261+
```
262+
263+
上面代码中,Here 文档相当于`echo`命令的重定向。
264+
265+
所以,Here 字符串只适合那些可以接受标准输入作为参数的命令,对于其他命令无效,比如`echo`命令就不能用 Here 文档作为参数。
257266
258267
```bash
259268
$ echo << _example_
@@ -275,12 +284,6 @@ Here 文档还有一个变体,叫做 Here 字符串(Here string),使用
275284
276285
它的作用是将字符串通过标准输入,传递给命令。
277286
278-
```bash
279-
$ md5sum <<< 'ddd'
280-
# 等同于
281-
$ echo 'ddd' | md5sum
282-
```
283-
284287
有些命令直接接受给定的参数,与通过标准输入接受参数,结果是不一样的。所以才有了这个语法,使得将字符串通过标准输入传递给命令更方便,比如`cat`命令只接受标准输入传入的字符串。
285288
286289
```bash
@@ -291,3 +294,11 @@ $ echo 'hi there' | cat
291294
292295
上面的第一种语法使用了 Here 字符串,要比第二种语法看上去语义更好,也更简洁。
293296
297+
```bash
298+
$ md5sum <<< 'ddd'
299+
# 等同于
300+
$ echo 'ddd' | md5sum
301+
```
302+
303+
上面例子中,`md5sum`命令只能接受标准输入作为参数,不能直接将字符串放在命令后面,会被当作文件名,即`md5sum ddd`里面的`ddd`会被解释成文件名。这时就可以用 Here 字符串,将字符串传给`md5sum`命令。
304+

0 commit comments

Comments
 (0)