type
status
date
slug
summary
tags
category
icon
password
URL
Sep 1, 2022 09:17 AM
Bash Shell脚本是一个纯文本文件,其中包含一组通常在命令行中键入的各种命令。它用于在Linux文件系统上自动执行重复性任务。它可能包含一组命令或一个命令,或者可能包含命令式编程的标志,例如循环,函数,条件构造等。实际上,Bash脚本是用Bash编程语言编写的计算机程序
- Bash脚本以
.sh
为结尾
- 开头声明
#!/bin/bash
- 使用
echo
来打印输出
./
作为前缀来执行脚本
Shebang 行
#!
后面就是脚本解释器的位置,Bash 脚本的解释器一般是/bin/sh
或/bin/bash
。执行权限和路径
只要指定了 Shebang 行的脚本,可以直接执行。这有一个前提条件,就是脚本需要有执行权限。可以使用下面的命令,赋予脚本执行权限
env 命令
env
命令总是指向/usr/bin/env
文件,或者说,这个二进制文件总是在目录/usr/bin
#!/usr/bin/env NAME
这个语法的意思是,让 Shell 查找$PATH
环境变量里面第一个匹配的NAME
。如果你不知道某个命令的具体路径,或者希望兼容其他用户的机器,这样的写法就很有用。
注释
Bash 脚本中,
#
表示注释,可以放在行首,也可以放在行尾。echo代码打印的信息脚本参数
调用脚本的时候,脚本文件名后面可以带有参数。
结果如下
甚至可以使用for循环
shift 命令
shift
命令可以改变脚本参数,每次执行都会移除脚本当前的第一个参数($1
),使得后面的参数向前一位,即$2
变成$1
、$3
变成$2
、$4
变成$3
,以此类推getopts 命令
getopts
命令用在脚本内部,可以解析复杂的脚本命令行参数,通常与while
循环一起使用,取出脚本所有的带有前置连词线(-
)的参数。它带有两个参数。第一个参数
optstring
是字符串,给出脚本所有的连词线参数。比如,某个脚本可以有三个配置项参数-l
、-h
、-a
,其中只有-a
可以带有参数值,而-l
和-h
是开关参数,那么getopts
的第一个参数写成lha:
,顺序不重要。注意,a
后面有一个冒号,表示该参数带有参数值,getopts
规定带有参数值的配置项参数,后面必须带有一个冒号(:
)。getopts
的第二个参数name
是一个变量名,用来保存当前取到的配置项参数,即l
、h
或a
。下面是一个例子。
上面例子中,
while
循环不断执行getopts 'lha:' OPTION
命令,每次执行就会读取一个连词线参数(以及对应的参数值),然后进入循环体。变量OPTION
保存的是,当前处理的那一个连词线参数(即l
、h
或a
)。如果用户输入了没有指定的参数(比如-x
),那么OPTION
等于?
。循环体内使用case
判断,处理这四种不同的情况。如果某个连词线参数带有参数值,比如
-a foo
,那么处理a
参数的时候,环境变量$OPTARG
保存的就是参数值。注意,只要遇到不带连词线的参数,
getopts
就会执行失败,从而退出while
循环。比如,getopts
可以解析command -l foo
,但不可以解析command foo -l
。另外,多个连词线参数写在一起的形式,比如command -lh
,getopts
也可以正确处理。变量
$OPTIND
在getopts
开始执行前是1
,然后每次执行就会加1
。等到退出while
循环,就意味着连词线参数全部处理完毕。这时,$OPTIND - 1
就是已经处理的连词线参数个数,使用shift
命令将这些参数移除,保证后面的代码可以用$1
、$2
等处理命令的主参数。配置项参数终止符 -
和
-
开头的参数,会被 Bash 当作配置项解释。但是,有时它们不是配置项,而是实体参数的一部分,比如文件名叫做f
或-file
。
上面命令的原意是输出文件
-f
和--file
的内容,但是会被 Bash 当作配置项解释。这时就可以使用配置项参数终止符
--
,它的作用是告诉 Bash,在它后面的参数开头的-
和--
不是配置项,只能当作实体参数解释。上面命令可以正确展示文件
-f
和--file
的内容,因为它们放在--
的后面,开头的-
和--
就不再当作配置项解释了。exit 命令
exit
命令用于终止当前脚本的执行,并向 Shell 返回一个退出值。上面命令中止当前脚本,将最后一条命令的退出状态,作为整个脚本的退出状态。
exit
命令后面可以跟参数,该参数就是退出状态。退出时,脚本会返回一个退出值。脚本的退出值,
0
表示正常,1
表示发生错误,2
表示用法不对,126
表示不是可执行脚本,127
表示命令没有发现。如果脚本被信号N
终止,则退出值为128 + N
。简单来说,只要退出值非0,就认为执行出错。下面是一个例子。
上面的例子中,
id -u
命令返回用户的 ID,一旦用户的 ID 不等于0
(根用户的 ID),脚本就会退出,并且退出码为1
,表示运行失败。exit
与return
命令的差别是,return
命令是函数的退出,并返回一个值给调用者,脚本依然执行。exit
是整个脚本的退出,如果在函数之中调用exit
,则退出函数,并终止脚本执行。命令执行结果
命令执行结束后,会有一个返回值。
0
表示执行成功,非0
(通常是1
)表示执行失败。环境变量$?
可以读取前一个命令的返回值。利用这一点,可以在脚本中对命令执行结果进行判断。
上面例子中,
cd /path/to/somewhere
这个命令如果执行成功(返回值等于0
),就删除该目录里面的文件,否则退出脚本,整个脚本的返回值变为1
,表示执行失败。由于
if
可以直接判断命令的执行结果,执行相应的操作,上面的脚本可以改写成下面的样子。更简洁的写法是利用两个逻辑运算符
&&
(且)和||
(或)。source 命令
source
命令用于执行一个脚本,通常用于重新加载一个配置文件。source
命令最大的特点是在当前 Shell 执行脚本,不像直接执行脚本时,会新建一个子 Shell。所以,source
命令执行脚本时,不需要export
变量。上面脚本输出
$foo
变量的值。上面例子中,当前 Shell 的变量
foo
并没有export
,所以直接执行无法读取,但是source
执行可以读取。source
命令的另一个用途,是在脚本内部加载外部库。上面脚本在内部使用
source
命令加载了一个外部库,然后就可以在脚本里面,使用这个外部库定义的函数。source
有一个简写形式,可以使用一个点(.
)来表示。别名,alias 命令
alias
命令用来为一个命令指定别名,这样更便于记忆。下面是alias
的格式。上面命令中,
NAME
是别名的名称,DEFINITION
是别名对应的原始命令。注意,等号两侧不能有空格,否则会报错。一个常见的例子是为
grep
命令起一个search
的别名。alias
也可以用来为长命令指定一个更短的别名。下面是通过别名定义一个today
的命令。有时为了防止误删除文件,可以指定
rm
命令的别名。上面命令指定
rm
命令是rm -i
,每次删除文件之前,都会让用户确认。alias
定义的别名也可以接受参数,参数会直接传入原始命令。上面例子中,别名定义了
echo
命令的前两个参数,等同于修改了echo
命令的默认行为。指定别名以后,就可以像使用其他命令一样使用别名。一般来说,都会把常用的别名写在
~/.bashrc
的末尾。另外,只能为命令定义别名,为其他部分(比如很长的路径)定义别名是无效的。直接调用
alias
命令,可以显示所有别名。unalias
命令可以解除别名。