Shell代码编写规范
2010-10-21 16:46:22 阿炯

随着写的Shell程序越来越多,发现自己每次写都有不同的习惯或者定义了不同的东西,变量名定义得不一样,整个程序缩进不统一,没有注释等问题,等我回过头看这些程序的时候发现很麻烦。所以写了个shell代码规范。

1.1 目的

定义Shell脚本命名和编码规范,统一管理Shell脚本,便于自己和别人查看,提高代码书写速度和美观,暂时只对自己进行约束,其它人只供参考。

1.2 开发工具

shell脚本是个文件,没有开发环境,FC4图形环境下,可用gedit、vi、vim、joe等,推荐使用vim因为这个最通用,他的功能同样是很强大,如果想在图形化下可以用gvim,并将环境设置为sh高亮显示。
方法如下:
1)cp /etc/vim/vimrc ~/.vimrc
2) vim ~/.vimrc 去掉”syntax on,Windows下可用ultraedit。文件保存时,有汉字提示的Shell脚本文件,文件保存时,字符编码必须为 GB18030/GBK/GB2132 (UTF-8) 三种格式之一。

2 对象命名规范

2.1 命名约定
1.本文档的命名约定是系统配置文件、脚本文件;

2.文件名、变量名、函数名不超过20个字符;

3.命名只能使用英文字母,数字和下划线,只有一个英文单词时使用全拼,有多个单词时,使用下划线分隔,长度较长时,可以取单词前3~4个字母。

4.文件名全部以小写命名,不能大小写混用(通过U盘交换文件时,大小写可能会丢失,即:大写文件名可能会全部变成小写文件名);

5.避免使用Linux的保留字如true、关键字如PWD等(见附表);

6.从配置文件导出配置时,要注意过滤空行和注释

2.2代码开头约定

1、第一行一般为调用使用的语言
2、下面要有这个程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、版权与是否开放共享GNU说明
8、最后是各版本的更新简要说明
如下面的例子:
#!/bin/bash
# -------------------------------------------------------------------------------
# Filename:    check_mem.sh
# Revision:    1.0
# Date:        2009/02/10
# Author:      AuthorMe
# Email:       authou@mail.com
# Website:     www.site.com
# Description: Plugin to monitor the memory of the system
# Notes:       This plugin uses the "" command
# -------------------------------------------------------------------------------
# Copyright:   2009 (c) Ajian
# License:     GPL
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# you should have received a copy of the GNU General Public License
# along with this program (or with Nagios);
#
# Credits go to Ethan Galstad for coding Nagios
# If any changes are made to this script, please mail me a copy of the changes
# -------------------------------------------------------------------------------
#Version 1.0
#The first one , can monitor the system memory

由于Shell没有很好的编辑环境,所以,建议用四个空格为基数进行缩进,好处在不同的环境下TAB可能代表的空格数不同,造成代码的错乱。用TAB他的优点是速度快方便,可以在编辑的时候也用TAB,但需要转换。

可以在更改编辑器,Windows的就不说了,主要是VIM
:set softtabstop=4

注意不要使用 :set tabstop=4 上面那个是同时把这一个TAB转换为四个空格,而这一条是定义TAB为四个空格,如果到其它编辑器上就会看到默认8个空格的情况,那就会不美观了。

另外将原有的TAB转换为空格,:retab

如果想让刚才的配置永久生效需要改动vim的配置文件 vim ~/.vimrc,更多详细的有用的配置见“VIM配置总结”

2.4 页宽

每行不要超过80字,如果超出,建议用“”折行,有管道的命令行除外。

2.5 环境变量

变量:全部是大写字母

变量引用:全部以变量名加双引号引用,如”$TERMTYPE”,或“${TERMTYPE}”,如果变量类型是数值型不引用,如:

如果需要从配置文件导出变量,则在变量前加一大写字母,以识别导出变量与自定义环境变量的区别,如:

变量值的引用尽量以$开头,如$(ls inst_*.sh),避免使用`ls inst_*。sh`

循环控制变量可以命名为单个字母, 比如 i、j等。 也可以是更有意义的名称, 比如 UserIndex。

环境变量和全局变量 在脚本开头定义。

函数中使用较多的文件,以环境变量的形式在文件开头定义,仅函数中使用的变量在函数开头定义

2.6 函数

函数以动名词形式存储,且第二个单词首字母要大写,如updateConfig()

每个函数控制在50-100行,超出行数建议分成两个函数

多次反复调用的程序最好分成函数,可以简化程序,使程序条理更清楚

2.7 语句

if 语句

if/then/else 语句中最可能被执行的部分应该放在 then 子句中, 不太可能被执行的部分应该放在 else 子句中。

如果可能, 尽量不要使用一连串的 if 语句, 而应该以 case 语句替代。

不要使 if 语句嵌套超过5层以上, 尽量以更清楚的代码替代。

case 语句

概要
case 语句中的单个子句应该以 case 常数的数字顺序或字母顺序排列。 子句中的执行语句应该尽量保持简单, 一般不要超过4到5行代码。 如果执行语句过于复杂, 应该将它放置在独立的函数中。

case 语句的 *) 子句应该只在正常的默认情况或检测到错误的情况下使用。

格式
case 语句遵循同样的缩进和命名约定。

while 语句

使用 Exit 过程退出 while 循环是不好的; 如果可能, 应该只使用循环条件来结束循环。

while 循环的所有初始化代码应该紧贴在进入 while 循环之前, 不要被其他无关语句分隔开。

循环结束后的处理应该紧跟在循环之后。

for 语句

如果需要执行确定次数的增量循环, 应该用 for 语句替代 while 语句。

2.8 信号捕捉

如果在进行重要配置修改时,应捕捉用户按键,如果用户按下Ctrl+C等重要操作终止程序,则调用回退程序,如:

2.9 关于注释

程序头应加注版本与功能说明的注释。但程序第一行不能汉字。

程序体中应包含必要的注释,注释说明如下:

单行注释,可以放在代码行的尾部或代码行的上部;

多行注释,用于注解复杂的功能说明,可以放在程序体中,也可以放在代码块的开始部分

代码修改时,对修改的内容要加必要版本注释及功能说明。


return与exit区别

exit  是用来结束一个程序的执行的,而return只是用来从一个函数中返回。

return 表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值,由return后面的参数指定,当然如果是在主函数main, 自然也就结束当前进程了,如果不是,那就是退回上一层调用。

return通常是必要的,因为函数调用的时候计算结果通常是通过返回值带出的。

如果函数执行不需要返回计算结果,也经常需要返回一个状态码来表示函数执行的顺利与否(-1和0就是最常用的状态码),主调函数可以通过返回值判断被调函数的执行情况。如果实在不需要函数返回什么值,就需要用void声明其类型。

补充:如果你函数名前有返回类型定义,如int,double等就必须有返回值,而如果是void型,则可以不写return,但这时即使写了也无法返回数值的。

exit()

exit(0)表示正常退出执行程序,如果加其它的数值:1,2,....可以表示由于不同的错误原因而退出。

那么,1,2,3怎么对应不同的原因?--你自己想让它是什么意思,它就是什么意思。但一般都有常用的、通用的含义:比如 0   一般都表示正常返回、退出。因此在main函数中exit(0)等价于return 0。


Linux Shell脚本25问


Q:1 Shell脚本是什么、它是必需的吗? 答:一个Shell脚本是一个文本文件,包含一个或多个命令。作为系统管理员,我们经常需要使用多个命令来完成一项任务,我们可以添加这些所有命令在一个文本文件(Shell脚本)来完成这些日常工作任务。

Q:2 什么是默认登录shell,如何改变指定用户的登录shell 答:在Linux操作系统,"/bin/bash"是默认登录shell,是在创建用户时分配的。使用chsh命令可以改变默认的shell。
示例如下所示:
# chsh <用户名> -s <新shell>
# chsh linuxtechi -s /bin/sh

Q:3 可以在shell脚本中使用哪些类型的变量?
答:在shell脚本,我们可以使用两种类型的变量:
系统定义变量 用户定义变量 系统变量是由系统系统自己创建的。这些变量通常由大写字母组成,可以通过"set"命令查看。
用户变量由系统用户来生成和定义,变量的值可以通过命令"echo $<变量名>"查看。
 
 Q:4 如何将标准输出和错误输出同时重定向到同一位置?
 答:这里有两个方法来实现:
 方法一:2>&1 (如# ls /usr/share/doc > out.txt 2>&1)
 方法二:&> (如# ls /usr/share/doc &> out.txt)

Q:5 shell脚本中"if"语法如何嵌套?
答:基础语法如下:
 if [ 条件 ] then 命令1 命令2 …..
else if [ 条件 ]
then 命令1 命令2 ….
else 命令1 命令2 …..
fi
fi

Q:6 shell脚本中"$?"标记的用途是什么?
答:在写一个shell脚本时,如果想要检查前一命令是否执行成功,在if条件中使用"$?"可以来检查前一命令的结束状态。简单的例子如下:
# ls /usr/bin/shar /usr/bin/shar
# echo $? 0
如果结束状态是0,说明前一个命令执行成功。
# ls /usr/bin/share ls: cannot access /usr/bin/share: No such file or directory

# echo $? 2 如果结束状态不是0,说明命令执行失败。

Q:7 在shell脚本中如何比较两个数字 ? 答:在if-then中使用测试命令 -gt 等来比较两个数字,例子如下:
#!/bin/bash
x=10 y=20
if [ x−gtx -gt x−gty ] then
echo "x is greater than y"
else echo "y is greater than x"
fi

Q:8 shell脚本中break命令的作用 ?
答:break命令一个简单的用途是退出执行中的循环。我们可以在while和until循环中使用break命令跳出循环。

Q:9 shell脚本中continue命令的作用 ?
答:continue命令不同于break命令,它只跳出当前循环的迭代,而不是整个循环。continue命令很多时候是很有用的,例如错误发生,但我们依然希望继续执行大循环的时候。

Q:10 告诉我shell脚本中Case语句的语法 ?
答:基础语法如下:
case 变量 in
值1)
命令1
命令2 …..
最后命令 !!
值2)
命令1
命令2 ……
最后命令
;
; esac

Q:11 shell脚本中while循环语法 ?
答:如同for循环,while循环只要条件成立就重复它的命令块。不同于for循环,while循环会不断迭代,直到它的条件不为真。
基础语法:
while [ 条件 ]
do 命令…
done

Q:12 如何使脚本可执行 ?
答:使用chmod命令来使脚本可执行。例子如下: # chmod a+x myscript.sh

Q:13 "#!/bin/bash"的作用 ?
 答:#!/bin/bash是shell脚本的第一行,称为释伴shebang行。这里#符号叫做hash,而!叫做 bang。它的意思是命令通过/bin/bash来执行。

Q:14 shell脚本中for循环语法 ?
答:for循环的基础语法: for 变量 in 循环列表 do 命令1 命令2 …. 最后命令 done

Q:15 如何调试shell脚本 ?
答:使用'-x'参数sh -x myscript.sh可以调试shell脚本。另一个种方法是使用‘-nv’参数(sh -nv myscript.sh)。

Q:16 shell脚本如何比较字符串?
答:test命令可以用来比较字符串。测试命令会通过比较字符串中的每一个字符来比较。

Q:17 Bourne shell(bash) 中有哪些特殊的变量 ?
答:下面的表列出了Bourne shell为命令行设置的特殊变量。

Q:18 在shell脚本中,如何测试文件 ?
答:test命令可以用来测试文件。基础用法如下表格:

Q:19 在shell脚本中,如何写入注释 ?
答:注释可以用来描述一个脚本可以做什么和它是如何工作的。每一行注释以#开头。例子如下:
#!/bin/bash # This is a command
echo "I am logged in as $USER"

Q:20 如何让 shell 就脚本得到来自终端的输入?
答:read命令可以读取来自终端使用键盘的数据。read命令得到用户的输入并置于你给出的变量中。
例子如下: # vi /tmp/test.sh
#!/bin/bash echo ‘Please enter your name’ read name
echo "My Name is $name"
# ./test.sh
Please enter your name LinuxTechi
My Name is LinuxTechi

Q:21 如何取消变量或取消变量赋值 ?
答:"unset"命令用于取消变量或取消变量赋值。语法如下所示: # unset <变量名>

Q:22 如何执行算术运算 ?
答:有两种方法来执行算术运算:
1.使用expr命令# expr 5 + 2
2.用一个美元符号和方括号[表达式],例如:test=[ 表达式 ]例如:test=[表达式]例如:test=[16 + 4] ; test=$[16 + 4]

Q:23 do-while语句的基本格式 ?
答:do-while语句类似于while语句,但检查条件语句之前先执行命令LCTT 译注:意即至少执行一次。下面是用do-while语句的语法
do { 命令 } while (条件)

Q:24 在shell脚本如何定义函数呢 ?
答:函数是拥有名字的代码块。当我们定义代码块,我们就可以在我们的脚本调用函数名字,该块就会被执行。示例如下所示:
$ diskusage () { df -h ; }
译注:下面是我给的shell函数语法,原文没有 [ function ] 函数名 [()] { 命令; [return int;] }

Q:25 如何在shell脚本中使用BCbash计算器 ?
答:使用下列格式,在shell脚本中使用bc: variable=`echo "options; expression" | bc`

参考原文:http://www.linuxtechi.com/linux-shell-scripting-interview-questions-answers/
作者:Pradeep Kumar
译文地址:https://linux.cn/article-5311-1.html
译者:Vic020