跳到主要内容

Shell 脚本编程

Shell 脚本通常不是复杂的程序,并且它是按行解释的。脚本第一行通常会以类似于 #!/bin/bash 开始,这段脚本用于通知 Shell 使用系统上的 Bourne Shell 解释器。

文件命名

  • Linux 不以文件后缀来区分文件类型,但为了便于日常管理和维护,shell 脚本习惯以 .sh 结尾。
  • 文件名全部以小写命名,不要大小写混用(不推荐驼峰命名法,大小写混用在特殊情况下会存在问题)。
  • 文件名尽可能做到“见名知意”;可以参考变量命名。

脚本的基本结构

一个脚本的基本结构是这样的:

#!SHEBANG

CONFIGURATION_VARIABLES

FUNCTION_DEFINITIONS

MAIN_CODE

Shebang

如果可能,请不要忘记shebang。

请小心使用/bin/sh作为shebang,在Linux系统中,/bin/sh就是Bash这是一个错误的观点。

于我而言,shebang有两个目的:

  • 说明直接执行时以哪个解释器来执行;
  • 明确该脚本应该以哪个解释器来执行;

配置变量

在这里,我将这一类变量——可以被用户更改的——叫做配置变量。

让这类变量容易找到,一般放在脚本的头部,给它们有意义的名称并且加上注释说明。正如上面说的,仅当你知道你为什么这么做的时候,才用大写的变量名形式,否则小写形式更加安全。

函数定义

所有函数定义应该在脚本主要代码执行之前,这样可以给人全局的印象,并且确保所有函数在使用之前它是已知的。

你应该使用可移植性高的函数定义形式,即不带function关键字的形式。

主程序

脚本参数

Shell 脚本允许你在运行它的同时给它传递参数,例如:

$ ./somescript.sh abcd 100

这两个参数,在脚本里面可以使用 $1$2 来获取,而 $0 代表的是脚本名字本身。

需要注意的一个细节是:当命令行参数超过 9 个,比如第 10 个参数,引用的时候必须使用花括号括起来,例如:${10},这种技术使得可以向脚本添加任意多个参数。

此外,我们还应该记住下面这些特殊的参数变量。

$# 特殊变量代表脚本运行时带有的命令行参数个数(不包含脚本名在内),对于上面的命令,$# 的值为 2。

这样的话,如果我们想知道最后一个参数的值,就可以利用这个特殊变量,而不需要知道总共有多少个参数。噔!噔!噔!—— ${$#}

$*$@ 变量的含义是相同的,它们会将命令行上提供的所有参数当作同一个字符串中的多个独立的单词。这样就可以使用 for 来遍历所有的值:

#!/bin/bash

count=1
for param in $*
do
echo "\$* : #$count = $param"
count=$(($count + 1))
done

我们输入 ./test.sh a b c ,其输出结果如下:

$* : #1 = a
$* : #2 = b
$* : #3 = c

脚本函数

函数的定义格式如下:

function_name()
{
commands
}

需要注意的是:

  • 函数没有返回值(事实上,所有的值都是字符串);
  • 函数名后面有一对圆括号,括号里面为空;
  • 函数的定义必须要在函数的调用之前;

虽然函数的定义中没有出现参数列表,但是在调用函数的时候,依然可以传参,像这样:

function_name 12 34

这样的话,在函数定义内部,我们就可以使用 $1$2 等等来表示传递过来的参数里。类似的,$0 表示函数本身的名字。

脚本行为和健壮性

  • 当脚本检测到问题时尽早退出,以免执行潜在的问题;
  • 如果你需要用到的命令可能并没有安装在系统上,在脚本执行的时候最好检查命令是否存在并且提醒用户缺少什么;
  • 采用有意义的脚本返回值,例如0代码成功,1代码错误或者失败;