规范的编程格式既可以使代码更加整洁,又能帮助别人理解使用代码,下面是在使用shell脚本的过程中涉及到的一些代码编程规范
命名
- 命名只能使用字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,不能使用标点符号,不能使用汉字,可以使用下划线 ,所以我们往往使用 作为分词的标识 例如 user_name、city_id 等
- 不能使用bash里的关键字(可用help命令查看保留关键字)
- 脚本中的所有变量风格统一使用下划线命名风格
目前关于命名使用较多的两种方式是
驼峰式
和下划线式
,两种命名规则见仁见智
local userName="Jeason"
local user_name="Jeason"
function log_info(){
# todo
}
function logInfo(){
# todo
}
function get_user_info(){
# todo
}
function getUserInfo(){
# todo
}
首行
推荐使用#!/usr/bin/env bash
,自动检测shell环境
注释
- 除脚本首行外,所有以
#
开头的语句都将成为注释。 - 函数必须有注释标识该函数的用途、入参变量、函数的返回值类型,且必须简单在一行内写完。
- 函数的注释
#
顶格写, 井号后面紧跟一个空格 ,对于该格式的要求是为了最后生成函数的帮助文档是用的(markdown语法),然后是注释的内容,注释尽量简短且在一行,最后跟的是函数的类型。 - 函数内注释
#
与缩进格式对整齐。 - 变量的注释紧跟在变量的后面
# 主函数 []<-() <-------函数注释这样写
function main(){
local var="Hello World!!!"
echo ${var}
}
# info级别的日志 []<-(msg:String) <-------带入参的函数注释
log_info(){
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')][$$]: [info] $*" >&2
}
# error级别的日志 []<-(msg:String) <-------带入参的函数注释
log_error(){
# todo [error]用红色显示 <------函数内注释
local msg=$1 # 将要输出的日志内容 <------变量的注释紧跟在变量的后面
if [[ x"${msg}" != x"" ]];then
# 注释 <-------函数内注释 `#` 与缩进格式对整齐
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')][$$]:[error] $*" >&2
fi
}
缩进
- 使用两个空格进行缩进,不适用tab缩进
- 不在一行的时候使用
\
进行换行,使用\
换行的原则是整齐美观
#!/usr/bin/env bash
# 脚本使用帮助文档 []<-()
manual(){
cat "$0"|grep -v "less \"\$0\"" \
|grep -B1 "function " \
|grep -v "\\--" \
|sed "s/function //g" \
|sed "s/(){//g" \
|sed "s/#//g" \
|sed 'N;s/\n/ /' \
|column -t \
|awk '{print $1,$3,$2}' \
|column -t
}
function search_user_info(){
local result=$(httpclient_get --cookie "${cookie}" \
"${url}/userName=${user_name}")
}
变量
- 变量赋值使用
=
等号,左右不能留有空格 - 使用变量的值用
$
取值符号 - 使用变量的时候,变量名一定要用
{}
包裹 - 使用变量的时候一定要用 双引号
"${}"
包裹
var1="Hello World" #正确,推荐使用双引号
var2='Hello World' #正确,不推荐使用单引号
var3="${var1}" #应用前面定义的变量的时候也要使用双引号包裹
var4=6
var5=6.70 #小数
var3=${var1} #正确,不推荐
- 常量一定要定义成
readonly
,这种变量不能使用source
跨shell使用 - 函数中的变量要用
local
修饰,定义成局部变量,这样在外部遇到重名的变量也不会影响 - 变量一经定义,不允许删除
变量类型
- 定义在函数中的我们称之为函数局部变量;定义在函数外部,shell脚本中变量我们称之为脚本全局变量
- 环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
函数
函数定义形式:
function main(){
#函数执行的操作
#函数的返回结果
}
或
main(){
#函数执行的操作
#函数的返回结果
}
- 使用关键字
function
显示定义的函数为public
的函数,可以供 外部脚本以sh 脚本 函数 函数入参
的形式调用 - 未使用关键字
function
显示定义的函数为privat
的函数, 仅供本脚本内部调用,注意这种privat
是人为规定的,并不是shell的语法,不推荐以sh 脚本 函数 函数入参
的形式调用,注意是不推荐而不是不能。 - 在函数内部首先使用有意义的变量名接受参数,然后在使用这些变量进行操作,禁止直接操作
$1
,$2
等,除非这些变量只用一次 - 函数的注释
函数类型的概念是从函数编程语言中的概念偷过来的,shell函数的函数类型指的是函数的输入到函数的输入的映射关系
# 主函数 []<-() <-------函数注释这样写
function main(){
local var="Hello World!!!"
echo ${var}
}
# info级别的日志 []<-(msg:String) <-------带入参的函数注释
log_info(){
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')][$$]: [info] $*" >&2
}
main
函数的函数类型是 []<-()
, <-
左侧表的是函数的返回值类型 用[]
包裹, 右侧是函数的参数类型 用()
包裹,多个参数用 ,
分隔,参数的描述是从 Scala 语言中偷过来, 先是参数名称 然后是参数类型 中间用:
分隔
对于main
函数的注释来说, #
顶格写,后面紧跟一个空格,其实这样写是遵循的markdown的语法, 后面再跟一个空格,然后是 []<-()
,代表这个函数没有入参也没有返回值,这个函数的目的就是执行这个这个函数中的命令,但我不关心这个函数的返回值。也就是利用函数的副作用来完成我们想要的操作
对于log_info
也是一样 不过 最后的函数类型是 []<-(msg:String)
代表入参是一个string
类型的信息,然后也没有返回值。关于函数的返回值,我理解的函数的返回值有两种形式,一种是显示的return
一种是隐式的echo
返回值
显式return
- 明确返回结果是在
[0-255]
之间的数值类型的时候使用显示reuturn
返回结果 - 返回结果类型是
Boolean
类型,也就是说函数的功能是起判断作用,返回结果是真或者假的时候使用显示return
返回结果
隐式echo
其他形式的输出使用echo
循环分支
if
if [[ condition ]]; then
# statements
fi
if [[ condition ]]; then
# statements
else
# statements
fi
if [[ condition ]]; then
# statements
elif [[ condition ]]; then
# statements
else
# statements
fi
if
后面的判断 使用 双中括号[[]]
if [[ condition ]]; then
写在一行
while
while [[ condition ]]; do
# statements
done
while read -r item ;do
# statements
done < 'file_name'
until
until [[ condition ]]; do
# statements
done
for
for (( i = 0; i < 10; i++ )); do
# statements
done
for item in ${array}; do
# statements
done
case
case word in
pattern )
#statements
;;
*)
#statements
;;
esac