11# Bash 脚本
22
3- Bash 脚本(script)就是一个包含一系列 Bash 命令的文件。Shell 读取这个文件,执行文件中的所有命令,就好像这些命令直接输入到命令行一样。所有能够在命令行中完成的任务,也能够用脚本来实现。
3+ 脚本(script)就是包含一系列命令的一个文件。Shell 读取这个文件,依次执行文件中的所有命令,就好像这些命令直接输入到命令行一样。所有能够在命令行中完成的任务,也能够用脚本来实现。
4+
5+ 脚本的好处是可以重复使用,也可以指定在特定场合自动调用,比如系统启动或关闭时。
46
57## Shebang 行
68
7- 脚本的第一行通常以` #! ` 字符开头,这个字符称为 Shebang,表示该文件是脚本。在 Shebang 后面是指定的脚本解释器,即使用什么程序执行该脚本,Bash 脚本的解释器一般是` /bin/sh ` 。
9+ 脚本的第一行通常约定是指定解释器,即这个脚本必须通过什么解释器执行。
10+
11+ 指定解释器的这一行以` #! ` 字符开头,这个字符称为 Shebang,所以这一行就叫做 Shebang 行。在` #! ` 后面就是脚本解释器的位置,Bash 脚本的解释器一般是` /bin/sh ` 。
812
913``` bash
1014#! /bin/sh
1115```
1216
13- 如果用户的 Bash 可执行文件不在 ` /bin/sh ` ,脚本就无法执行了。为了保险,可以写成下面这样。
17+ 如果用户的 Bash 可执行文件不是 ` /bin/sh ` ,脚本就无法执行了。为了保险,可以写成下面这样。
1418
1519``` bash
1620#! /usr/bin/env bash
1721```
1822
19- 上面命令使用` /usr/bin/env ` 命令,返回 Bash 的可执行文件 。` env ` 命令的详细介绍,请看后文。
23+ 上面命令使用` /usr/bin/env ` 命令,返回 Bash 可执行文件的位置 。` env ` 命令的详细介绍,请看后文。
2024
2125每个脚本都应包含一个 Shebang 行。如果缺少该行,就需要手动调用解释器。举例来说,脚本是` script.sh ` ,有 Shebang 行的时候,可以直接调用执行。
2226
2327``` bash
2428$ ./script.sh
2529```
2630
31+ 上面例子中,` script.sh ` 是脚本文件名。脚本通常使用` .sh ` 后缀名,不过这不是必需的。
32+
2733如果没有 Shebang 行,就只能手动调用解释器执行。
2834
2935``` bash
@@ -32,31 +38,58 @@ $ /bin/sh ./script.sh
3238$ bash ./script.sh
3339```
3440
35- 上面命令中,最后一行的` bash ` 命令一般是` /bin/sh ` 的别名。
41+ ## 执行权限和路径
42+
43+ 前面说过,通过 Shebang 行指定解释器的脚本,可以直接执行。这有一个前提条件,就是脚本需要有执行权限。可以使用下面的命令,赋予脚本执行权限。
44+
45+ ``` bash
46+ $ chmod +x script.sh
47+ ```
3648
37- ## 脚本的执行权限
49+ 除了执行权限,脚本调用时,一般需要指定脚本的路径。如果将脚本放在环境变量 ` $PATH ` 指定的目录中,就不需要指定路径了。因为 Bash 会自动到这些目录中,寻找是否存在同名的可执行文件。
3850
39- 脚本如果要直接执行,除了必须有 Shebang 行以外,还需要有执行权限。可以使用下面的命令,赋予脚本执行权限 。
51+ 建议在主目录新建一个 ` ~/bin ` 子目录,专门存放可执行脚本,然后把 ` ~/bin ` 加入 ` $PATH ` 。
4052
4153``` bash
42- $ chmod +x ./script.sh
54+ export PATH= $PATH : ~ /bin
4355```
4456
45- 脚本调用的时候,一般需要指定脚本的路径。如果将脚本放在环境变量 ` $PATH ` 指定的目录中,就不需要指定路径了。建议可以主目录里面新建一个 ` ~/bin ` 目录,专门存放可执行脚本,然后把 ` ~/bin ` 加入 ` $PATH ` 。
57+ 上面命令改变环境变量 ` $PATH ` ,将 ` ~/bin ` 添加到 ` $PATH ` 的末尾。可以将这一行加到 ` ~/.bashrc ` 文件里面,然后重新加载一次 ` .bashrc ` ,这个配置就可以生效了 。
4658
4759``` bash
48- $ export PATH= $PATH : ~ /bin
60+ $ source ~ /.bashrc
4961```
5062
51- 上面命令的意思是,改变环境变量 ` $PATH ` ,在可执行文件的目录清单中加入 ` ~/bin ` ,然后所有当前 Shell 的子 Shell 都可以获得这个新的环境变量 ` $PATH ` 。Bash 脚本总是在一个新建的子 Shell 里面执行,所以就可以直接输入脚本文件名,来运行脚本 。
63+ 以后不管在什么目录,直接输入脚本文件名,脚本就会执行 。
5264
5365``` bash
5466$ script.sh
5567```
5668
57- 上面的命令没有指定脚本路径,因为` script.sh ` 在` $PATH ` 指定的目录中。
69+ 上面命令没有指定脚本路径,因为` script.sh ` 在` $PATH ` 指定的目录中。
70+
71+ ## env 命令
72+
73+ ` env ` 命令总是指向` /usr/bin/env ` 文件。` #!/usr/bin/env NAME ` 这种语法的意思是,让 Shell 查找` $PATH ` 环境变量里面第一个匹配的` NAME ` 。如果你不知道某个命令的路径,这样的写法就很有用。` /usr/bin/env bash ` 的意思就是,返回` bash ` 可执行文件的位置,前提是` bash ` 的路径是在` $PATH ` 里面。
74+
75+ 其他脚本文件也可以使用这个命令。比如 Node.js 脚本的 Shebang 行,可以写成下面这样。
76+
77+ ``` bash
78+ #! /usr/bin/env node
79+ ```
80+
81+ ` env ` 命令的参数如下。
82+
83+ - ` -i ` , ` --ignore-environment ` :不带环境变量启动
84+ - ` -u ` , ` --unset=NAME ` :从环境变量中删除一个变量
85+ - ` --help ` :显示帮助
86+ - ` --version ` :输出版本信息
87+
88+ 下面是一个例子,新建一个不带任何环境变量的Shell。
5889
59- 这种命令行直接改写` $PATH ` 变量的做法,一旦退出了当前 Shell,就会失效。如果你希望长期有效,可以这行` export ` 命令写入主目录下面的` .bash_profile ` 文件或` .profile ` 文件(取决于发行版)。
90+ ``` bash
91+ $ env -i /bin/sh
92+ ```
6093
6194## 注释
6295
@@ -69,39 +102,28 @@ echo 'Hello World!'
69102echo ' Hello World!' # 井号后面的部分也是注释
70103```
71104
72- ## 启动顺序
73-
74- 每一个 Bash 脚本启动的时候,会读取一系列配置文件。这分成登录 Shell 和非登录 Shell 两种情况。
105+ 建议在脚本开头,使用注释说明当前脚本的作用,这样有利于日后的维护。
75106
76- 登录 Shell 读取配置文件的顺序如下。
107+ ## 脚本的调试
77108
78- - ` /etc/profile ` :所有用户的全局配置。
79- - ` ~/.bash_profile ` :用户的个人配置,可用于扩展或覆盖全局配置。
80- - ` ~/.bash_login ` :如果找不到` ~/.bash_profile ` ,Bash 则尝试读取此文件。
81- - ` ~/.profile ` :如果找不到` ~/.bash_profile ` 和` ~/.bash_login ` ,Bash 尝试读取此文件。
109+ 脚本执行过程中,有时为了方便调试,需要显示当前执行的命令。这时可以使用` bash ` 命令的` -x ` 参数,该参数在执行每一条命令时,都会将该命令先打印出来。
82110
83- 非登录 Shell 读取配置文件的顺序如下 。
111+ 下面是一个脚本 ` script.sh ` 。
84112
85- - ` /etc/bash.bashrc ` :所有用户的全局配置。
86- - ` ~/.bashrc ` :用户的个人配置,可用于扩展或覆盖全局配置。
87-
88- 除了读取上面的配置文件之外,非登录 Shell 还会从它的父进程继承环境变量。
113+ ``` bash
114+ # script.sh
115+ echo hello world
116+ ```
89117
90- 普通用户对 Shell 的配置修改,一般写在 ` ~/.bashrc ` 文件里面。非登录 Shell 默认会读取这个文件,而登录 Shell 大多数情况下也会通过变通方法读取该文件。比如, ` .bash_profile ` 文件通常会像下面这样写 。
118+ 加上 ` -x ` 参数,执行每条命令之前,都会显示该命令 。
91119
92120``` bash
93- # .bash_profile
94- # Get the aliases and functions
95- if [ -f ~ /.bashrc ]; then
96- . ~ /.bashrc
97- fi
98-
99- # User specific environment and startup programs
100- PATH=$PATH :$HOME /bin
101- export PATH
121+ $ bash -x script.sh
122+ + echo hello world
123+ hello world
102124```
103125
104- 上面代码中,如果 ` ~/.bashrc ` 文件存在,就会执行这个文件。这就是“登录 Shell”读取 ` ~/.bashrc ` 的方法。另外,最后两行的作用是在环境变量 ` $PATH ` 里面,追加 ` $HOME/bin ` 目录,然后 ` export ` 命令的作用是将这个变量输出给当前 Shell 的所有子进程 。
126+ 上面例子中,行首为 ` + ` 的行,显示该行是所要执行的命令,下一行才是该命令的执行结果 。
105127
106128## 脚本参数
107129
@@ -268,31 +290,6 @@ funct_1 () {
268290}
269291```
270292
271- ## env 命令
272-
273- ` env ` 命令的可执行文件总是在` /usr/bin ` 目录里面,作用是在指定环境之中运行一个程序。` /usr/bin/env bash ` 的意思是,找到` bash ` 的可执行文件,然后在 Bash 环境中运行脚本。
274-
275- 相应的,如果要执行Node脚本,可以写成下面这样。
276-
277- ``` bash
278- #! /usr/bin/env node
279- ```
280-
281- ` #!/usr/bin/env NAME ` 这种语法的意思是,命令 Shell 查找` $PATH ` 环境变量里面第一个匹配的` NAME ` 。如果你不知道某个命令的路径,这样的写法就很有用。它的好处是,只要` bash ` 的路径是在` $PATH ` 路径里面,就总是能找到它。
282-
283- ` env ` 命令的参数如下。
284-
285- - ` -i ` , ` --ignore-environment ` :不带环境变量启动
286- - ` -u ` , ` --unset=NAME ` :从环境变量中删除一个变量
287- - ` --help ` :显示帮助
288- - ` --version ` :输出版本信息
289-
290- 下面是一个例子,新建一个不带任何环境变量的Shell。
291-
292- ``` bash
293- $ env -i /bin/sh
294- ```
295-
296293## exit 命令
297294
298295` exit ` 命令用于终止当前脚本的执行,并向 Shell 返回一个退出值。
0 commit comments