Bash 脚本
Bash 脚本
脚本(script)就是包含一系列命令的一个文本文件。Shell 读取这个文件,依次执行里面的所有命令,就好像这些命令直接输入到命令行一样。所有能够在命令行完成的任务,都能够用脚本完成。所以 Bash 脚本其实也没什么复杂的。
脚本的好处是可以重复使用,也可以指定在特定场合自动调用,比如系统启动或关闭时自动执行脚本。
在服务运维领域,Bash 脚本的编写是绕不开的,服务器运维人员必须掌握 Bash 脚本。
脚本编写 IDE
如果我们在 Windows 环境下用 txt 格式编写 Bash 脚本,因为 Windows 操作系统下的文件,每一行的结尾是\n\r
,而在 Linux 下文件的每一行的结尾是\n
,所以上传到 Linux 系统后,需要运行sed -i 's/\r$//' filename.sh
进行换行符的替换。
每次都这么做,未免太麻烦了,工欲善其事必先利其器,我们不如准备好 Bash 的 Windows 开发环境。
IDEA
首先要安装的是 Bash 的脚本插件神器 BashSupport Pro,只要在 Jetbrain 家的 IDE 中安装这个插件即可,最好是 IDEA。
注意,这个插件时付费的,不过价格也不贵,一年 23 美元,可以先试用一个月,以后需要这个插件了再按月买也可以,一个月才 2.3 美元,装了这个插件,相当于买了一个开发 Bash 的专业 IDE,还是十分划得来的
此外注意,启用这个插件的时候,会自动把 IDEA 默认自带的
Shell Script
插件禁用掉,如果不再使用BashSupport Pro
,记得把 IDEA 自带的Shell Script
插件启用。而且如果不再使用
BashSupport Pro
插件,所有的.sh
的文件的换行符都会自动从LF
换成CRLF
,我们需要手动将其再切换回LF
,不然sh
的文件在 Linux 环境下都无法正常执行。根本原因是因为不再使用BashSupport Pro
插件之后,IDEA 将不再支持识别拓展名为.sh
的文件,此后新建的sh
文件换行符都是CRLF
。
在 IDEA 中,我这里采用Remote Development with Run Targets的方式来开发,即本地开发 shell 脚本,在远端的 Linux 环境下执行,关于如何配置,看教程即可。
通过
Run Targets
来远程开发的一点不好就是调试的时候需要传输很多文件,有需要的话,可以在远端 Linux 环境中安装 rsync,不过我为了不破坏远端 Linux 的环境,就没装。这样,远程调试完之后,只需要删除在Run Targets
中配置的Project path on target
中填写的目录即可。
其余的远程开发方式请看官方文档:Remote Development with BashSupport Pro – BashSupport Pro,
VSCode
IDEA 中编写 Bash 脚本还是太重了,而且插件还要收费。
在 VSCode 中通过安装以下插件即可可以实现很方便的编辑:
-
shellman
-
ShellCheck
-
shell-format
-
Bash IDE
在 Windows 操作系统下,VSCode 无法很好地实现运行调试,想要实现运行调试,首先需要安装 WSL,然后安装以下插件:
- Bash Debug
以上插件可通过直接下载BASH Extension Pack
打包下载。
在 VSCode 中编写 Bash 脚本的时候,直接新建后缀为.sh
的文件,然后用 VSCode 打开(此时 VSCode 默认采用LF
作为换行符),进行编辑,而不是直接编辑临时文件。
Shebang 行
脚本的第一行通常是指定解释器,即这个脚本必须通过什么解释器执行。这一行以#!
字符开头,这个字符称为 Shebang,所以这一行就叫做 Shebang 行。
#!
后面就是脚本解释器的位置,Bash 脚本的解释器一般是/bin/sh
或/bin/bash
。
|
|
#!
与脚本解释器之间有没有空格,都是可以的。
如果 Bash 解释器不放在目录/bin
,脚本就无法执行了。为了保险,可以写成下面这样。
|
|
上面命令使用env
命令(这个命令总是在/usr/bin
目录),返回 Bash 可执行文件的位置。env
命令的详细介绍,请看后文。
在《Bash 变量》中也有对
env
命令的描述在本章的
env
小节中有对 env 命令的具体解析
Shebang 行不是必需的,但是建议加上这行。如果缺少该行,就需要手动将脚本传给解释器。举例来说,脚本是script.sh
,有 Shebang 行的时候,可以直接调用执行。
|
|
上面例子中,script.sh
是脚本文件名。脚本通常使用.sh
后缀名,不过这不是必需的。
如果没有 Shebang 行,就只能手动将脚本传给解释器来执行。
|
|
执行权限和路径
前面说过,只要指定了 Shebang 行的脚本,可以直接执行。这有一个前提条件,就是脚本需要有执行权限。可以使用chmod
命令,赋予脚本执行权限。
关于
chmod
的具体语法,请看《Linux 实操篇 - 组管理和权限管理》的修改权限 - chmod
小节
当用户在 A 脚本中通过
.
或者source
调用 B 脚本的时候,用户只需要有 A 的执行即可,没有 B 的执行权限依旧可以调用,但是如果直接执行 B 脚本,没有权限则会直接报错,提示Permission denied
此外,我们还可以通过[ -x file ]
来判断当前用户是否有执行权限。简单实践如下:
创建ts.sh
,但是不赋予权限
|
|
创建run_shell.sh
|
|
赋予执行权限
|
|
此时,我们直接调用run_shell.sh
,就会自动赋权,然后执行
|
|
再次调用,因为已经赋权,所以只会输出文字
|
|
实际上,因为我们有
run_shell.sh
的执行权限,因此在run_shell.sh
中调用ts.sh
是不需要执行权限的,这里只是为了演示这个过程
从上面的例子中,我们可以注意到,脚本调用时,一般需要指定脚本的路径,如果你就在脚本所在的路径,你可以直接使用./run_shell.sh
来执行脚本,如果你在根路径下面,而脚本在/opt/shell_script/run_shell.sh
这个路径下面,你需要这样执行脚本。
|
|
显然这样就很不方便,此时,如果将脚本放在环境变量$PATH
指定的目录中,就不需要指定路径了。因为 Bash 会自动到这些目录中,寻找是否存在同名的可执行文件。
建议在主目录新建一个~/script
子目录,专门存放可执行脚本。
然后把~/script
加入$PATH
环境变量中。
|
|
上面命令改变环境变量$PATH
。将~/script
添加到$PATH
的末尾。
可以将这一行加到~/.bash_profile
文件里面:
关于配置文件的加载过程,请看《Bash 启动时的配置文件加载》
|
|
然后重新加载一次.bash_profile
,这个配置就可以生效了。
|
|
然后我们将我们想要全局可执行的脚本都放到这个~/script
下,比如ts.sh
,赋予权限之后,在任何路径下输入脚本名称(包括拓展名)即可直接执行,例如
|
|
执行脚本的方式
我们前面用的都是./
这种方式
详细修改一下./
这种说法
总的来说执行脚本的方式有以下几种:
-
source script.sh
或. script.sh
-
sh script.sh
或bash script.sh
-
/path/script.sh
/path/script.sh
这种方式最常用的格式是在脚本所在目录下直接调用./script.sh
,这种方式也是我们最常用的方式。
而sh script.sh
或者bash script.sh
跟/path/script.sh
本质上一样,因此总的来说方法分为两类:
-
通过
source
执行脚本 -
通过
bash
执行脚本
区别是什么
-
source
: 用法:source FileName
;作用:在当前 bash 环境下读取并执行 FileName 中的命令。该 filename 文件可以无 “执行权限”,即没有x
权限。注:该命令通常用命令.
来替代。 -
sh
、bash
:用法:sh FileName
、bash FileName
;作用:打开一个子 shell 来读取并执行 FileName 中命令。该 filename 文件可以无 “执行权限”。注:运行一个 shell 脚本时会启动另一个命令解释器。这种方式运行的脚本,不需要在第一行指定解释器信息,写了也会被忽略掉。其实解释器也是有参数的,比如你可以通过添加-l
参数来让子 shell 成为一个非交互式的登录式 shell,例如bash -l test.sh
,我们也可以直接将这个参数写到脚本里,比如#!/bin/bash -l
,然后用./
执行,效果是一样的
关于何时创建子 shell,请看《Bash 子 shell》
关于/path/script.sh
,这种方式,多说一句,跟sh script.sh
或bash script.sh
的区别是,这种方式要求我们在脚本的第一行写上要用哪个解释器#!/bin/bash
,我们也可以给他带上解释器参数,像这样#!/bin/bash -l
,这样,可以获得一个非交互式的登录式的 shell。
注意,在执行当前目录下的script.sh
,一定要写成./script.sh
,而不是script.sh
,运行其它二进制的程序也一样。
直接写script.sh
,linux 系统会去 PATH 环境变量里寻找有没有叫script.sh
的,而默认只有/bin
, /sbin
, /usr/bin
,/usr/sbin
等目录在 PATH 里,也就是只有这些目录下的命令才能通过直接输入名字来调用,你的当前目录通常不在 PATH 里,所以写成script.sh
是会找不到命令的,要用./script.sh
告诉系统说,就在当前目录找。
如果你在需要执行别的目录下的脚本的话,你就得将./
换成从当前目录到脚本所在目录的完整目录,确保能找到脚本。
如果你实在是需要全局调用script.sh
,那就得将其放到 PATH 环境变量种,方式在执行权限和路径
小节中已经演示过了。
source 命令
source
命令用于执行一个脚本,通常用于重新加载一个配置文件。
|
|
source
命令最大的特点是在当前 Shell 执行脚本,即不会创建一个子 shell 所以,source
命令执行脚本时,不需要export
变量。
当我们直接执行脚本的时候,比如
./script.sh
,会新建一个子 Shell。此时传递环境变量就需要使用export
命令关于何时创建子 shell,请看《Bash 子 shell》
|
|
上面脚本输出$foo
变量的值。
|
|
上面例子中,当前 Shell 的变量foo
并没有export
,所以直接执行无法读取,但是source
执行可以读取。
source
命令的另一个用途,是在脚本内部加载外部库或者调用其他脚本。
|
|
上面脚本在内部使用source
命令加载了一个外部库,然后就可以在脚本里面,使用这个外部库定义的函数。
source
有一个简写形式,可以使用一个点(.
)来表示。
|
|
env 命令
env
命令总是指向/usr/bin/env
文件,或者说,这个二进制文件总是在目录/usr/bin
。
#!/usr/bin/env NAME
这个语法的意思是,让 Shell 查找$PATH
环境变量里面第一个匹配的NAME
。如果你不知道某个命令的具体路径,或者希望兼容其他用户的机器,这样的写法就很有用。
/usr/bin/env bash
的意思就是,返回bash
可执行文件的位置,前提是bash
的路径是在$PATH
里面。其他脚本文件也可以使用这个命令。比如 Node.js 脚本的 Shebang 行,可以写成下面这样。
|
|
env
命令的参数如下。
-i
,--ignore-environment
:不带环境变量启动。-u
,--unset=NAME
:从环境变量中删除一个变量。--help
:显示帮助。--version
:输出版本信息。
下面是一个例子,新建一个不带任何环境变量的 Shell。
|
|
注释
Bash 脚本中,#
表示注释,可以放在行首,也可以放在行尾。
|
|
建议在脚本开头,使用注释说明当前脚本的作用,这样有利于日后的维护。
脚本参数
调用脚本的时候,脚本文件名后面可以带有参数。
|
|
上面例子中,script.sh
是一个脚本文件,word1
、word2
和word3
是三个参数。
脚本文件内部,可以使用特殊变量,引用这些参数。
-
$0
:脚本所在路径加文件名:path/script.sh
,一般为./script.sh
。可通过basename
命令获取文件名 -
$#
:参数的总数。 -
$1
~$9
:对应脚本的第一个参数到第九个参数。 -
$@
:全部的参数,参数之间使用空格分隔。 -
$*
:全部的参数,参数之间使用变量$IFS
值的第一个字符分隔,默认为空格,但是可以自定义。关于,请看《Bash read 命令》中的
IFS 变量
小节
如果脚本的参数多于 9 个,那么第 10 个参数可以用${10}
的形式引用,以此类推。
注意,如果命令是command -o foo bar
,那么-o
是$1
,foo
是$2
,bar
是$3
。
如果想要通过
script.sh -name val
这种形式传递参数,请参考本章的getopts 命令
小节,这也是我们写脚本比较常用的传参方式
简单实践:
创建shell_params.sh
|
|
chmod
赋权之后执行
|
|
我们也可以用 for 循环的方式来遍历参数,修改shell_params.sh
|
|
赋权之后执行
|
|
注意,脚本传参是做不到传递数组变量的,只能做到将所有的数组元素挨个传入,然后再在脚本中组合成一个数组。
简单实践如下:
创建script_param.sh
|
|
赋权后执行:
|
|
shift 命令
shift
命令可以改变脚本参数,每次执行都会移除脚本当前的第一个参数($1
),使得后面的参数向前一位,即$2
变成$1
、$3
变成$2
、$4
变成$3
,以此类推。
shift
命令可以接受一个整数作为参数,指定所要移除的参数个数,默认为1
。
简单实践:
创建shell_params.sh
|
|
赋权后执行
|
|
getopts 命令
getopts
命令用在脚本内部,可以解析复杂的脚本命令行参数,通常与while
循环一起使用,取出脚本所有的带有前置连词线(-
)的参数。但是不支持--
开头的参数。
|
|
它带有两个参数。第一个参数optstring
是字符串,给出脚本所有的连词线参数。比如,某个脚本可以有三个配置项参数-s
、-n
、-v
,其中-n
和-v
可以带有参数值,而-s
是开关参数,那么getopts
的第一个参数写成sn:v:
,顺序不重要。注意,n
和v
后面有一个冒号,表示该参数带有参数值,getopts
规定带有参数值的配置项参数,后面必须带有一个冒号(:
)。如果这个冒号在开头,比如:sn:v:
,则表示不打印错误信息。getopts
的第二个参数name
是一个变量名,用来保存当前取到的配置项参数,即s
、n
或v
。
简单实践
shell_params.sh
|
|
在《Bash 字符串操作》的
字符串头部的模式匹配
小节,我们了解过basename
和dirname
赋权后执行
|
|
错误传参
|
|
可以看到
上面例子中,while
循环不断执行getopts 'sn:v:' OPTION
命令,每次执行就会读取一个连词线参数(以及对应的参数值),然后进入循环体。变量OPTION
保存的是,当前处理的那一个连词线参数(即s
、n
或v
)。如果用户输入了没有指定的参数(比如-x
),那么OPTION
等于?
。循环体内使用case
判断,处理这四种不同的情况。
如果某个连词线参数带有参数值,比如-n foo
,那么处理a
参数的时候,环境变量$OPTARG
保存的就是参数值。
注意,只要遇到不带连词线的参数,getopts
就会执行失败,从而退出while
循环。比如,getopts
可以解析command -n foo
,但不可以解析command foo -n
。另外,多个连词线参数写在一起的形式,比如command -sn
,getopts
也可以正确处理。
变量$OPTIND
在getopts
开始执行前是1
,然后每次执行就会加1
。等到退出while
循环,就意味着连词线参数全部处理完毕。$OPTIND - 1
就是已经处理的连词线参数个数,这时,你可以通过使用shift
命令将这些参数移除,然后只使用你已经从参数中提取了的参数,比如$name
、$value
。或者你也可以留着原始参数,然后通过位置比如$1
、$2
、$3
等变量来访问他们,不过一般情况下我们都会通过shift
删除掉,因为通常情况下,可以通过-
来传参的时候,参数的位置是没有规律的,通过位置来获取执行参数没有意义。
getopts 在解析传入 Shell 脚本的参数时(也就是
$@
),并不会执行 shift 操作,而是通过变量 OPTIND 来记住接下来要解析的参数的位置。getopts 在解析到选项的参数时,就会将参数保存在 OPTARG 变量当中;如果 getopts 遇到不合法的选项,择把选项本身保存在 OPTARG 当中。
getopt 命令
getopts
:Bash 内置,支持大多数复杂命令,不支持长选项,而getopt
支持长选项,getopt
较getopts
更强大,其不仅支持短参-s
,还支持-–longopt
的长参数,甚至支持--longopt
的简化参数。相较于getopts
,getopts
不但支持长短选项,其还支持选项和参数放在一起写。
getopt
用法:
|
|
选项说明:
-a
:使getopt
长参数支持” - “符号打头,必须与-l 同时使用
-l
:后面接 getopt 支持长参数列表
-n
:program:如果 getopt 处理参数返回错误,会指出是谁处理的这个错误,这个在调用多个脚本时,很有用
-o
:后面接短参数列表,这种用法与 getopts 类似
-u
:不给参数列表加引号,默认是加引号的(不使用-u 选项),例如在加引号的时候 –longoption“arg1 arg2” ,只会取到”arg1”,而不是完整的”arg1 arg2”
简单实践一下:
创建脚本shell_long_params.sh
|
|
赋权并执行:
|
|
用起来很方便。
脚本参数规范
在创建 shell 脚本时,尽量保持选项与 Linux 通用的选项含义相同,Linux 通用选项有
-a
:显示所有对象
-c
:生产一个计数
-d
:指定一个目录
-e
:扩展一个对象
-f
:指定读入数据的文件
-h
:显示命令的帮助信息
-i
:忽略文本大小写
-l
:产生输出得长格式文本
-n
:使用非交互模式
-o
:指定将所有输出重定向到输出文件
-q
:以安静模式运行
-r
:递归的处理目录和文件
-s
:以安静模式运行
-v
:生成详细输出
-x
:排除某个对象
-y
:对所有问题回答 yes
配置项参数终止符
Bash Shell 有三种解析参数的方式:
- 手工处理:大多数简单的命令
getopts
: 大多数复杂命令,不支持长选项getopt
: 支持长选项,getopts
和getopt
功能相似但又不完全相同,其中getopt
是独立的可执行文件,而getopts
是由 Bash 内置的
这三种方式我们前面都学习了。
在学习getopts
和getopt
的时候我们就知道,以-
或者--
开头的参数,虽然是一个参数,但是本质上来说是一个配置项,会被getopts
和getopt
解析,而不会被手工处理的方式解析,那如果-
和--
开头的参数不是配置项,而是实体参数的一部分,比如文件名叫做-f
或--file
。
|
|
上面命令的原意是输出文件-f
和--file
的内容,但是会被 Bash 当作配置项解释。
这时就可以使用配置项参数终止符--
,它的作用是告诉 Bash,在它后面的参数开头的-
和--
不是配置项,只能当作实体参数解释。
|
|
上面命令可以正确展示文件-f
和--file
的内容,因为它们放在--
的后面,开头的-
和--
就不再当作配置项解释了。
如果要确保某个变量不会被当作配置项解释,就要在它前面放上参数终止符--
。
实际上我们要创建出名称为-f
的文件,也要用到参数终止符--
。
|
|
一个实际的例子,如果想在文件里面搜索--hello
,这时也要使用参数终止符--
。
|
|
上面命令在example.txt
文件里面,搜索字符串--hello
。这个字符串是--
开头,如果不用参数终止符,grep
命令就会把--hello
当作配置项参数,从而报错。
退出脚本执行
参考教程:Shell 中 exit 和 return 的区别_恋喵大鲤鱼的博客-CSDN 博客
exit 命令
exit
命令是 Shell 内建命令,用于退出当前 Shell 进程。使用格式如下:
|
|
可以指定退出状态 N,N 的取值范围是 0-255,一般情况下,0 表示正常退出,非零表示异常退出。如果状态码是 0-255 之外的数值,则会被强制转换为 uint8_t 类型的数值,比如 -1 会被转换为 255,256 会发生类型宽度截断,被转换为 0。状态码 N 可以不指定,默认是上一条命令的退出码。
关于状态码值的定义尚未有统一的标准,但是结束程序时随意的指定一个状态码是一个不好的行为,应该使用统一的状态码。这样便于调用者更具状态码快速粗略地推断出被调的状态,而不用去查找状态码的具体含义。当然实际的状态码值可以自定义,项目中统一即可,但还是推荐使用 GNU C 的头文件 <sysexits.h>
中对状态码的定义。
exit
命令可用于终止当前脚本的执行,并向 Shell 返回一个退出值。这个退出值可以写在exit
后面手动指定,也可以不手动指定,此时会将当前脚本最后一条命令的退出状态,作为整个脚本的退出状态。
|
|
退出时,脚本会返回一个退出值。脚本的退出值,0
表示正常,1
表示发生错误,2
表示用法不对,126
表示不是可执行脚本,127
表示命令没有发现。如果脚本被信号N
终止,则退出值为128 + N
。简单来说,只要退出值非 0,就认为执行出错。
下面是一个例子。
|
|
上面的例子中,id -u
命令返回用户的 ID,一旦用户的 ID 不等于0
(根用户的 ID),脚本就会退出,并且退出码为1
,表示运行失败。
当我们用exit
命令退出脚本执行的时候,我们可以在交互式终端的下一个语句中,通过$?
这个变量获取脚本中exit
命令的退出值,通过不同的退出值来判断不同的错误类型。
关于
$?
变量的解释,请看本章的命令 / 脚本执行结果
小节。
通过 SSH 打开交互式终端之后,输入exit
,可以退出 SSH,即退出 Shell 进程。
return 命令
return
是语言级别的一个关键字,用于结束函数并返回一个结果。return
不带参数时,则会返回函数体中最后一个命令的返回值(这一点跟exit
命令一样)。
return
也可以用于使用.
或source
的方式包含的子 Shell 脚本中,用于退出子脚本的执行,可以返回指定的状态或者脚本中最后一个命令的exit status
。退出子脚本的执行之后,父脚本的 Shell 进程不会中止,会继续往后执行。
比如如下脚本:
|
|
输出
|
|
也就是说,只能在从方法中返回或者从子脚本中返回的时候,才可以使用return
sourced script
A 脚本通过
.
或者source
调用了 B 脚本,那么 B 脚本就叫 sourced script,可以在 B 中通过return
退出 A 对 B 的调用,退出之后,A 继续往后执行。
exit 与 return 的区别
-
作用不同。
exit
用于在程序运行的过程中随时结束程序,exit
的参数是返回给 OS 的。exit
是结束一个进程,它将删除进程使用的内存空间,同时把错误信息返回父进程。而return
是返回函数值并退出函数; -
语义层级不同。
return
是语言级别的,它表示了调用堆栈的返回;而exit
是系统调用级别的,它表示了一个进程的结束; -
使用方法不用。
return
一般用在函数方法体内,exit
可以出现在 Shell 脚本中的任意位置。
在脚本中调用其他脚本
其实方法跟执行脚本的方式
中提到的方法是一样的,即source script.sh
/. script.sh
、sh script.sh
/bash script.sh
、/path/script.sh
,而通过sh
或者bash
跟直接输入脚本路径执行脚本本质上一样,
因此总的来说方法分为两类:
-
.
和source
:这两种方式都不需要考虑变量传递的问题,因为他们没有创建子 shell,而是将指定的脚本内容拷贝至当前的脚本中,由一个 Shell 进程来执行。在 shell 脚本中,我们最常用的就是这种方式。 -
bash
或者sh
:这种方式实际上就是新开了一个 shell 进程来执行另一个脚本,这就需要考虑父 shell 到子 shell 的变量传递问题,因此需要使用export
来传递变量,
在通过.
执行另一个脚本的时候,在另一个脚本中执行exit
的时候,父脚本也会退出。但是在另一个脚本中执行return
的时候只会退出子脚本,回到父脚本中继续往后执行。
换个角度说,在 Bash 脚本通过source
或者.
调用别的脚本,可以看做是对别的脚本的引用,就跟 Javascript、或者 Python 中通过 import 调用其他脚本是一个概念。
命令 / 脚本执行结果
命令或脚本执行结束后,会有一个返回值。0
表示执行成功,非0
(通常是1
)表示执行失败。环境变量$?
可以读取前一个命令的返回值。
我们在本章的
退出脚本执行
小节中提到过退出码
关于
$?
变量的解释,请看《Bash 变量》的特殊变量
小节
利用这一点,可以在脚本中对命令执行结果进行判断。
我们在编写 shell 脚本的时候,经常通过此变量来判断前一个命令是否执行成功,此时需要注意,想要正确地获取前一个命令的执行结果,对$?
的获取必须紧接上一条命令,中间隔着一个 if 判断都是不行的,必须得是上下两句的关系才行。
比如这样,$?
是无法获取dataview_single_machine_install.sh
或者dataview_cluster_install.sh
的执行结果的,因为还隔着一个 if 判断
|
|
只有这样才行,$?
才可以正确获取dataview_single_machine_install.sh
或者dataview_cluster_install.sh
的执行结果
|
|
简单实践一下:
|
|
上面例子中,cd /path/to/somewhere
这个命令如果执行成功(返回值等于0
),就删除该目录里面的文件,否则退出脚本,整个脚本的返回值变为1
,表示执行失败。
由于if
可以直接判断命令的执行结果,执行相应的操作,上面的脚本可以改写成下面的样子。
|
|
更简洁的写法是利用两个逻辑运算符&&
(且)和||
(或)。
|
|
但是注意,不要通过cd $val
这样来切换目录
|
|
上面脚本中,只有cd $dir_name
执行成功,才会执行rm *
。但是,如果变量$dir_name
为空,cd
就会进入用户主目录,从而删光用户主目录的文件。
下面的写法才是正确的。
|
|
上面代码中,先判断目录$dir_name
是否存在,然后才执行其他操作。
脚本日志
我们可以将脚本中所有的输出和异常,全部输出到指定的日志文件中,具体做法,请看《Bash 函数》的参数变量
小节的例子,很完整。
脚本模板
参考《set 命令和 shopt 命令》和《mktemp 命令和 trap 命令》
标准格式:
|
|
alias 命令
我们在《alias 别名》中已经学习过
alias
命令了
alias
命令用来为一个命令指定别名,这样更便于记忆和使用。下面是alias
的格式。
|
|
上面命令中,NAME
是别名的名称,DEFINITION
是别名对应的原始命令。注意,等号两侧不能有空格,否则会报错。
一个常见的例子是为grep
命令起一个search
的别名。
|
|
alias
也可以用来为长命令指定一个更短的别名。下面是通过别名定义一个today
的命令。
|
|
有时为了防止误删除文件,可以指定rm
命令的别名。
|
|
上面命令指定rm
命令是rm -i
,每次删除文件之前,都会让用户确认。
alias
定义的别名也可以接受参数,参数会直接传入原始命令。
|
|
上面例子中,别名定义了echo
命令的前两个参数,等同于修改了echo
命令的默认行为。
指定别名以后,就可以像使用其他命令一样使用别名。一般来说,都会把常用的别名写在~/.bashrc
的末尾。另外,只能为命令定义别名,为其他部分(比如很长的路径)定义别名是无效的。
关于
~/.bashrc
,请看《Bash 启动时的配置文件加载》
直接调用alias
命令,可以显示所有别名。
|
|
unalias
命令可以解除别名。
|
|