跳到主要内容

脚本基本结构

正式编写脚本前需要先熟悉一下脚本中的基本结构,良好的结构组织有助于编写,阅读和维护。

注释

注释以 # 号开头,一行的末尾也可以添加注释,但是行尾注释并不被推荐,会降低可读性,令整个脚本文件看上去很凌乱。

# 我是一行好看的注释
whoami  # 我是一行很挫的注释
# TODO 这个需求暂时做不了

通过 HERE DOCUMENT 也可以达到注释的效果

<< 'EOF'
老司机在干嘛
老司机在干吗
老司机在干骂
EOF

虽然以上也达到了注释的效果,但是并不建议这样使用,简简单单用#号就挺好,别整那些花里胡哨的。

缩进

有无缩进对脚本的执行并没有影响,在shell中缩进仅仅是为了可读性。可以通过空格或者tab来增加代码行的缩进,但是需要注意的是只要世界上还存在程序员这个物种,那么tab党和空格党之间的纷争就永远不会停止。我总结的生存法则是保持和他人一致,例如,如果代码属于公司,那么就和公司编码规范一致,如果是其他人主导的项目,那就和项目风格一致,如果是你主导的项目,那你就可以让别人和你保持一致。

但是需要注意的是同一个仓库尽量保持只有一种缩进方式,要么空格要么tab,有一个流传百年的故事:

程序员: “医生,我最近总感觉身体不舒服...”
医生:   “你在工作和生活中有什么不好的习惯吗?”
程序员: “好像没啥,不过我写代码经常会混用TAB和空格...”
医生:   “那你感觉这样做对身体造成了什么影响,能否举个例子?”
程序员想了想,说: “不举...”

我个人推荐的脚本缩进是4个空格,例如vim可以设置成set ts=4 sw=4 expandtab

函数

函数是一个很好的组织脚本结构的方法,可以消除重复和降低代码复杂度。当你的代码显得特别臃肿,阅读起来有些吃力,或者出现了明显的重复代码的时候,就应该用函数重新组织一下了。函数能接收位置参数,能通过局部变量限制变量的作用域,函数名被存在一个内置的名为 FUNCNAME 的变量中,方便对脚本进行调试。

定义一个函数通常可以有以下两种方式

function 我是一个函数 {
    do something
}

或者

我是一个正经的函数() {
    do something
}

两种方式都能正常运行,我比较推荐第二种写法,因为看上去干净又卫生而且可以少敲6个字符。

shell函数支持嵌套,也就是函数里面再定义函数,但是没有局部函数的说法,例如在函数A里面定义了函数B,那么当外层调用了一次函数A,函数B就也能四处被调用。

shell函数也支持递归调用,例如

#!/bin/bash

sequence() {
    local start=$1
    local end=$2
    local value=${value:-$start}
    echo $value
    ((value++))
    [[ $value -le $end ]] && sequence $start $end
}

sequence 1 10

这个函数通过递归调用实现了类似seq命令的功能。

注意事项

一个脚本中通常可以把全局变量写到最前面,中间部分是各种函数,结尾是对函数的调用。除非必要,不要在两个函数的中间夹杂一些变量定义或者执行逻辑,这样会导致脚本很难维护,比如下面这种就是反例

func1() {
    xxx
}

do 了 something
a=1
do 了 something else

func2() {
    xxx
}