因为 shell 脚本语法比较灵活,写 shell 脚本的开发者熟悉的编程语言也有较大差异,大家很容易写出风格迥异的代码出来。如果只有自己一个人用还好,如果是大家合作开发同一个项目,代码风格不同就会造成不小的麻烦。所以约定一个代码风格是很有必要的。
本文中的代码风格约定只是我的个人建议,可以根据自己的需求或者喜好来调整。本文的代码风格约定,在一定程度上也适用于 bash。
注意需要有丰富 shell 编程经验的人制定和维护代码风格约定,不然很容易无法执行或者流于形式而解决不了实际问题。代码风格约定不只需要约定代码怎么写,而且要说明为什么要这么写,不然容易因为难以服众而无法推广。
原因:
cat
less
diff
等命令都将 tab 显示成 8 个空格的宽度,有些命令是不可配置的(即使可配置,要让所有机器配置同步也是件麻烦的事情)。如果自己在编辑器上配置 tab 为 4 个或者 2 个空格,那么就会和 cat
less
等命令的显示方法不一致,会导致很多麻烦。原因:
diff
之类工具对代码进行分析处理也不方便,所以需要约定最长字符数。\
折行,折行后缩进一层(4 个空格)。aa && bb || cc
、[[ ]]
或者 (( ))
中折行,&&
||
放在下一行的行首。原因:
&&
和 ||
在逻辑上属于后半个语句,在自然语言中也是这样,比如 明天我去公园或者去逛街
,如果需要拆成两个子句,那么会是 明天我去公园,或者去逛街
,而不是 明天我去公园或者,去逛街
。对代码来说也是一样。而且把 &&
或 ||
放在行首更容易对齐,看起来更舒服。+
&&
|
等双元运算符左右要加一个空格。!
~
等一元运算符和作用对象之间不加空格。( )
和 (( ))
{ }
内侧不加空格,[[ ]]
因为语法需要,内侧加一个空格。;
之前不加空格,之后加一个空格。(( ))
中调用函数时),函数名和 (
之间不加空格。if
while
等关键字和后边的内容之间加一个空格。if [[ ]] {
等场景中,{
和前边的内容之间加一个空格。[ ]
之间不加空格,用 [ ]
取数组或者哈希表值时,[ ]
内侧不加空格。>
<
等重定向符号和文件或者文件描述符之间不加空格。原因:
#!/bin/zsh
后加一个空行。if
while
等语句块之后加一个空行。原因:
[ ]
,用 [[ ]]
代替。$(( ))
而不是 $[ ]
。原因:
[ ]
的功能没有 [[ ]]
丰富,而且二者的用法存在差异,混合使用容易出问题。$[ ]
的功能没有 $(( ))
丰富,混合使用容易出问题。[ ]
在各种地方功能不一致,非必要场景尽量避免使用。原因:
$var
取变量值时,两边不加双引号,除非需要将非字符串变量转换成字符串。${var}
中的大括号。local
定义)还是全局变量(用 typeset -g
定义)。local
定义)。原因:
$var
读取变量内容时,不用因为变量不存在、值为空、包含特殊符号而产生各种逻辑错误,所以无需在两端加双引号。$var
读变量是很多编程语言都有的用法,而 ${var}
几乎是 shell 中特有的用法,并且输入更麻烦,没必要推广这种用法。而且因为不加大括号导致变量名粘连而出错的情况,编写代码时即可识别出来,和外部输入无关,不需要为了避免不存在的问题而输入很多额外的大括号。原因:
name()
或者 function name()
定义函数,但同一个文件中风格要一致。原因:
name()
定义函数,那么没有照顾 JavaScript 等编程语言开发者的习惯,而且 function
关键字有助于代码的搜索。function name()
定义函数,需要额外输入 9 个字符,而意义有限,投入比产出要大。原因:
原因:
本系列教程语句风格实例:
if [[ ... ]] {
} elif ((...)) {
} else {
}
case $i {
(a)
...
;;
(*)
...
;;
}
POSIX shell 语句风格实例:
if [[ ... ]]; then
elif ((...)); then
else
fi
case $i in
(a)
...
;;
(*)
...
;;
esac
本文介绍了我建议的 zsh 代码风格,可以适当参考。